package org.jsola.hr.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.jsola.admin.dto.HeaderFieldsAddDTO;
import org.jsola.admin.entity.DictItemDO;
import org.jsola.admin.entity.HeaderFieldsDO;
import org.jsola.admin.entity.HeaderFieldsTemplateDO;
import org.jsola.common.DateKit8;
import org.jsola.core.Page;
import org.jsola.exception.ParamException;
import org.jsola.hr.common.DateUtils;
import org.jsola.hr.common.ExcelKit;
import org.jsola.hr.common.HrLogKit;
import org.jsola.hr.constant.*;
import org.jsola.hr.dao.*;
import org.jsola.hr.dto.*;
import org.jsola.hr.dto.excel.SocListExportDTO;
import org.jsola.hr.entity.*;
import org.jsola.hr.provider.IAdminProviderService;
import org.jsola.hr.query.*;
import org.jsola.hr.service.*;
import org.jsola.hr.vo.*;
import org.jsola.hr.vo.excel.EmpSocDetailsExportVO;
import org.jsola.hr.vo.excel.FieldItemGroupVO;
import org.jsola.hr.vo.excel.FieldItemVO;
import org.jsola.salary.common.StringKit;
import org.jsola.user.core.TokenUser;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

import static org.jsola.hr.constant.EmpSocConstant.*;
import static org.jsola.hr.constant.EmpSocStatus.*;
import static org.jsola.hr.constant.HrConstants.*;
import static org.jsola.hr.constant.SocPayCostType.*;

/**
 * @author lyh
 */
@Service("hrEmpSocTransformServiceImpl")
public class EmpSocTransformServiceImpl implements IEmpSocTransformService {

    @Autowired
    private IEmpSocInfoService empSocInfoService;

    @Autowired
    private IEmpSocItemService empSocItemService;

    @Autowired
    private IEmpSocTransformDAO empSocTransformDAO;

    @Autowired
    private IEmpSocMonthService empSocMonthService;

    @Autowired
    private IEmpSocMonthDAO empSocMonthDAO;

    @Autowired
    private ISocProgService socProgService;

    @Autowired
    private ISocProgItemService socProgItemService;

    @Autowired
    private IEmpInfoService empInfoService;

    @Autowired
    private IEmpSocItemDAO empSocItemDAO;

    @Autowired
    private IEmpSocInfoDAO empSocInfoDAO;

    @Autowired
    private IPersonalEventService personalEventService;

    @Autowired
    private ICostBillService costBillService;

    @Autowired
    private IEmpSocRelatedService empSocRelatedService;

    @Autowired
    private IEmpSocPlanService empSocPlanService;

    @Autowired
    private ICompanyService companyService;

    @Autowired
    private ISocDifferenceService socDifferenceService;

    @Autowired
    private IAdminProviderService adminProviderService;

    private static final String POST_TYPE = "POST_TYPE";

    @Override
    public Page<EmpSocTransformVO> selectEmpSocList(EmpSocTransformQuery empSocTransformQuery, TokenUser tokenUser) {
        buildEmpSocListQuery(empSocTransformQuery);
        PageInfo<EmpSocTransformVO> empSocListPageInfo = PageHelper.startPage(empSocTransformQuery.getPageNo(),
                empSocTransformQuery.getPageSize()).doSelectPageInfo(() ->
                empSocTransformDAO.selectEmpSocList(empSocTransformQuery, tokenUser.getSiteId()));
        if (CollectionUtils.isEmpty(empSocListPageInfo.getList())) {
            return new Page<>(empSocTransformQuery.getPageSize(), empSocTransformQuery.getPageNo());
        }
        Page<EmpSocTransformVO> empSocPage = new Page<>(empSocListPageInfo.getList(), empSocTransformQuery.getPageNo(),
                empSocTransformQuery.getPageSize(), (int) empSocListPageInfo.getTotal());
        //此时查询出来的人员是没有金额的,需要去info表拿到这个人的最新的一条数据赋值
        socListAmountInfo(empSocPage.getEntities(), empSocTransformQuery.getCompanyId(), tokenUser);
        return empSocPage;
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public void fillGather(FillSocQuery fillSocQuery, TokenUser tokenUser) {
        Date fillGatherStartDate = fillSocQuery.getFillGatherStartDate();
        Date fillGatherEndDate = fillSocQuery.getFillGatherEndDate();
        String companyId = fillSocQuery.getCompanyId();
        List<String> empIdList = fillSocQuery.getEmpIdList();
        ParamException.notEmpty(empIdList, "请选择补收人员");
        Map<String, EmpInfoDO> empMap = empInfoService.selectDoByIds(empIdList)
                .stream().collect(Collectors.toMap(EmpInfoDO::getId, v -> v));
        SocProgDO socProgDO = socProgService.selectDOById(fillSocQuery.getSocProgId(), tokenUser.getSiteId());
        // 根据参保方案和付款归属计算补收金额,拿到这个参保方案的社保子项
        List<SocProgItemDO> empSocItemDOList = fillSocQuery.getEmpSocItemDOList();
        empSocItemDOList = empSocItemDOList.stream()
                .filter(socProgItemDO -> {
                    if ("缴费合计".equals(socProgItemDO.getItemName())) {
                        return false;
                    }
                    return SOC_ITEM_TYPE.equals(socProgItemDO.getItemType()) ||
                            ME_ITEM_TYPE.equals(socProgItemDO.getItemType());
                }).collect(Collectors.toList());
        ParamException.notEmpty(empSocItemDOList, "该参保方案暂无社保子项,无法进行社保补收");
        //补收 只补收社保,获取补收开始和补收结束时间之间的月份
        List<Date> monthGather = DateUtils.getMonthDifferences(fillGatherStartDate, fillGatherEndDate);
        // 计算每个月的补收滞纳金 (平均)
        List<BigDecimal> fines = calculateFines(fillSocQuery.getFine(), monthGather.size());
        String currentMonthId = fillSocQuery.getMonthId();
        checkCostBillByMonthId(currentMonthId, fillSocQuery.getMonth(), tokenUser);
        String startDate = DateUtils.getYearMonthByDate(fillGatherStartDate);
        String endDate = DateUtils.getYearMonthByDate(fillGatherEndDate);
        // 每个人每个月都要创建一条或者更新一条参保记录
        List<EmpSocRelatedDO> empSocRelatedList = empSocRelatedService
                .selectByEmpIdList(empIdList, tokenUser.getSiteId());
        Map<String, EmpSocRelatedDO> relatedMap = empSocRelatedList.stream()
                .collect(Collectors.toMap(EmpSocRelatedDO::getEmpId, v -> v));
        for (String empId : empIdList) {
            EmpSocRelatedDO empSocRelated = relatedMap.get(empId);
            EmpInfoDO empInfoDO = empMap.get(empId);
            for (int i = 0; i < monthGather.size(); i++) {
                Date date = monthGather.get(i);
                String[] yearAndMonth = DateUtils.getYearAndMonth(date);
                String month = empSocMonthService.selectMonthIdByYearAndMonth(companyId,
                        yearAndMonth[0], yearAndMonth[1], tokenUser.getSiteId());
                // 判断是否有正常参保记录
                EmpSocInfoDO exitInfo = empSocInfoService.selectInfoByMonthId(empId, month, tokenUser);
                if (!ObjectUtils.isEmpty(exitInfo)) {
                    throw new ParamException("员工" + empInfoDO.getName() + yearAndMonth[1] + "月已参保不可补收");
                }
                // 判断该月份是否存在补收记录
                String empSocInfoId = empSocInfoService.selectEmpIsHaveFillCollect(SUPPLEMENT_TYPE_ONE, yearAndMonth[0],
                        yearAndMonth[1], empInfoDO.getId(), currentMonthId, companyId, tokenUser.getSiteId());
                ParamException.isFalse(StringKit.isNotBlank(empSocInfoId), "员工" + empInfoDO.getName() +
                        yearAndMonth[1] + "月存在补收记录，请勿重复添加!");
                // 查询参保月中的这个月此人有没有补缴过,有就加入,没有就新创建
                empSocInfoId = empSocInfoService.selectEmpIsHaveFillCollect(SUPPLEMENT_TYPE_TWO, yearAndMonth[0], yearAndMonth[1],
                        empInfoDO.getId(), currentMonthId, companyId, tokenUser.getSiteId());
                // 如果有补缴记录  更新
                if (!StringUtils.isEmpty(empSocInfoId)) {
                    EmpSocInfoDO empSocInfoDOUpdate = empSocInfoService.selectDOById(empSocInfoId, tokenUser.getSiteId());
                    // 根据付款归属计算金额
                    gatherAmountByPayAttribution(socProgDO, empSocItemDOList, empSocInfoDOUpdate,
                            fillSocQuery.getPayAttribution(), SOC_ITEM_TYPE);
                    String supplementType = SUPPLEMENT_TYPE_ONE + empSocInfoDOUpdate.getSupplementType();
                    empSocInfoDOUpdate.setSupplementType(supplementType);
                    empSocInfoDOUpdate.setSocialSecurityFine(fines.get(i));
                    empSocInfoDOUpdate.setEmpSocStatus(empSocRelated.getSocState());
                    empSocInfoDOUpdate.setEmpMeStatus(empSocRelated.getMeState());
                    empSocInfoDOUpdate.setEmpPfStatus(empSocRelated.getPfState());
                    empSocInfoDOUpdate.setServiceCost(empSocInfoDOUpdate.getServiceCost().add(fillSocQuery.getServiceCost()));
                    empSocInfoService.updateByIdSelective(empSocInfoDOUpdate, tokenUser.getSiteId(), tokenUser.getUserId());
                } else {
                    EmpSocInfoDO empSocInfoInsert = new EmpSocInfoDO();
                    empSocInfoInsert.setCompanySocAmount(new BigDecimal("0"));
                    empSocInfoInsert.setPersonalSocAmount(new BigDecimal("0"));
                    // 根据付款归属计算金额
                    gatherAmountByPayAttribution(socProgDO, empSocItemDOList, empSocInfoInsert,
                            fillSocQuery.getPayAttribution(), SOC_ITEM_TYPE);
                    customEmpSocInfoDO(empSocInfoInsert, empInfoDO, currentMonthId, companyId,
                            socProgDO, yearAndMonth, fillSocQuery, SUPPLEMENT_TYPE_ONE, fines.get(i));
                    empSocInfoInsert.setEmpSocStatus(empSocRelated.getSocState());
                    empSocInfoInsert.setEmpMeStatus(empSocRelated.getMeState());
                    empSocInfoInsert.setEmpPfStatus(empSocRelated.getPfState());
                    EmpSocInfoDO empSocInfoDO = empSocInfoService
                            .save(empSocInfoInsert, tokenUser.getSiteId(), tokenUser.getUserId());
                    empSocInfoId = empSocInfoDO.getId();
                }
                // 保存完参保管理记录,保存参保子项
                List<EmpSocItemDO> empSocItemInsertList = new ArrayList<>();
                for (SocProgItemDO empSocItemDO : empSocItemDOList) {
                    EmpSocItemDO empSocItemDOInsert = new EmpSocItemDO();
                    BeanUtils.copyProperties(empSocItemDO, empSocItemDOInsert);
                    empSocItemDOInsert.setEmpSocId(empSocInfoId);
                    previewFillItemAmount(socProgDO, empSocItemDOInsert, empSocItemDO, fillSocQuery.getPayAttribution(), tokenUser);
                    empSocItemInsertList.add(empSocItemDOInsert);
                }
                if (!CollectionUtils.isEmpty(empSocItemInsertList)) {
                    empSocItemDAO.insertListAndSetId(empSocItemInsertList);
                }
            }
            //用工档案
            String desc = "由管理员" + tokenUser.getUserName() + "办理社保补收,起始年月为" + startDate + ",终止年月为" + endDate +
                    "费用归属为" + SocPayAttribution.find(fillSocQuery.getPayAttribution()).getDesc();
            personalEventService.autoSave(empInfoDO.to(EmpInfoVO.class), tokenUser, desc,
                    PersonalEventEnum.FILL_GATHER.getValue(), PersonalEventEnum.FILL_GATHER.getDesc());
        }
        HrLogKit.logForSave("由管理员" + tokenUser.getUserName() + "进行社保补收," +
                        "起始年月为" + startDate + ",终止年月为" + endDate, "EmpSocInfo",
                companyId, companyId, tokenUser);
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public String fillDifference(FillSocQuery fillSocQuery, TokenUser tokenUser) {
        StringBuilder result = new StringBuilder();
        //补差两步工作 1:修改参保方案子表中的基数 2:添加缴费记录和个人缴费子项记录
        //1:
        //新建一个Map容器,存储子项名称和子项的对应关系,准备下面计算补差金额
        Map<String, SocProgItemUpdateDTO> itemNameCardinalityMap = new HashMap<>(32);
        for (SocProgItemUpdateDTO socProgItemUpdateDTO : fillSocQuery.getFillDifferenceItem()) {
            SocProgItemDO socProgItemDO = new SocProgItemDO();
            socProgItemDO.setId(socProgItemUpdateDTO.getId());
            if (fillSocQuery.getOnlySocAmount()) {
                socProgItemDO.setCardinalityDefaultAmount(socProgItemUpdateDTO.getCardinalityDefaultAmount());
                socProgItemDO.setAmountCompany(socProgItemUpdateDTO.getAmountCompany());
                socProgItemDO.setAmountPersonal(socProgItemUpdateDTO.getAmountPersonal());
            } else {
                socProgItemDO.setCardinalityDefault(socProgItemUpdateDTO.getCardinalityDefault());
                socProgItemDO.setCardinalityMin(socProgItemUpdateDTO.getCardinalityMin());
                socProgItemDO.setCardinalityMax(socProgItemUpdateDTO.getCardinalityMax());
            }

            socProgItemService.updateByIdSelective(socProgItemDO, tokenUser.getSiteId(), tokenUser.getUserId());
            itemNameCardinalityMap.put(socProgItemUpdateDTO.getItemName(), socProgItemUpdateDTO);
        }
        // 查询当前用工单位最后创建的参保月
        EmpSocMonthDO empSocMonthDO = empSocMonthDAO.selectMaxDate(fillSocQuery.getCompanyId(), tokenUser.getSiteId());
        SocProgDO socProgDO = socProgService.selectDOById(fillSocQuery.getSocProgId(), tokenUser.getSiteId());
        //获取补差开始和补差结束时间之间的月份
        List<Date> monthDifferences = DateUtils.getMonthDifferences(fillSocQuery.getFillDifferenceStartDate(),
                fillSocQuery.getFillDifferenceEndDate());
        // 循环需要补差的每个月
        for (Date monthDifference : monthDifferences) {
            String[] yearAndMonth = DateUtils.getYearAndMonth(monthDifference);
            // 查询这个月的monthId
            String monthDifferenceId = empSocMonthService.selectMonthIdByDate(fillSocQuery.getCompanyId(),
                    monthDifference, tokenUser.getSiteId());
            if (StringUtils.isEmpty(monthDifferenceId)) {
                continue;
            }
            // 查询这个月用这个方案的人,或者补收补缴传这个月的人
            List<EmpSocInfoDO> empSocInfoList = empSocInfoService.selectInfoByMonthAndScheme(monthDifferenceId,
                    socProgDO.getId(), yearAndMonth[0], yearAndMonth[1], tokenUser.getSiteId());
            List<String> empIdList = empSocInfoList.stream().map(EmpSocInfoDO::getEmpId).collect(Collectors.toList());
            Map<String, EmpSocInfoDO> empSocInfoMap = empSocInfoList.stream().collect(Collectors.toMap(EmpSocInfoDO::getEmpId, v -> v));
            List<EmpSocRelatedDO> empSocRelatedList = empSocRelatedService
                    .selectByEmpIdList(empIdList, tokenUser.getSiteId());
            Map<String, EmpSocRelatedDO> relatedMap = empSocRelatedList.stream()
                    .collect(Collectors.toMap(EmpSocRelatedDO::getEmpId, v -> v));
            for (String empId : empIdList) {
                EmpSocRelatedDO empSocRelated = relatedMap.get(empId);
                String id = UUID.randomUUID().toString().replace("-", "").toUpperCase();
                EmpSocInfoDO empSocInfoDO = new EmpSocInfoDO();
                // 默认已确认
                empSocInfoDO.setId(id);
                empSocInfoDO.setPlanFlag(true);
                empSocInfoDO.setEmpId(empId);
                empSocInfoDO.setProgId(socProgDO.getId());
                empSocInfoDO.setCompanyId(fillSocQuery.getCompanyId());
                empSocInfoDO.setEmpSocStatus(empSocRelated.getSocState());
                empSocInfoDO.setEmpMeStatus(empSocRelated.getMeState());
                empSocInfoDO.setEmpPfStatus(empSocRelated.getPfState());
                empSocInfoDO.setMonthId(empSocMonthDO.getId());
                empSocInfoDO.setYear(yearAndMonth[0]);
                empSocInfoDO.setMonth(yearAndMonth[1]);
                // 缴费类型为补差
                empSocInfoDO.setPayCostType(FILL_DIFFERENCE.getValue());
                // 计算金额,这里需要拿到这个人这个月的缴费记录
                EmpSocInfoDO monthDifferenceInfo = empSocInfoMap.get(empId);

                BigDecimal personalSocAmount = new BigDecimal("0");
                BigDecimal personalPfAmount = new BigDecimal("0");
                BigDecimal companySocAmount = new BigDecimal("0");
                BigDecimal companyPfAmount = new BigDecimal("0");
                // 获取里面的子项,计算补差金额
                List<EmpSocItemDO> empSocItemDOList = empSocItemService.
                        selectEmpSocItemByInfoId(monthDifferenceInfo.getId(), tokenUser.getSiteId());
                List<EmpSocItemDO> insertItemList = new ArrayList<>();
                for (EmpSocItemDO empSocItemDO : empSocItemDOList) {
                    SocProgItemUpdateDTO socProgItemUpdateDTO = itemNameCardinalityMap.get(empSocItemDO.getItemName());
                    if (ObjectUtils.isEmpty(socProgItemUpdateDTO)) {
                        continue;
                    }
                    // 拿到传进来的 此子项的新基数
                    BigDecimal bigDecimal = socProgItemUpdateDTO.getCardinalityDefault();
                    // 先判断 这个参保方案是否只设置参保金额
                    if (fillSocQuery.getOnlySocAmount()) {
                        // 如果只设置参保金额 这里只需要用传进来的此子项的 个人公司金额,减去 本来的 个人公司金额
                        BigDecimal personalAmount = socProgItemUpdateDTO.getAmountPersonal()
                                .subtract(empSocItemDO.getAmountPersonal());
                        BigDecimal companyAmount = socProgItemUpdateDTO.getAmountCompany()
                                .subtract(empSocItemDO.getAmountCompany());
                        if (personalAmount.compareTo(BigDecimal.ZERO) == 0 &&
                                companyAmount.compareTo(BigDecimal.ZERO) == 0) {
                            continue;
                        }
                        empSocItemDO.setAmountPersonal(personalAmount);
                        empSocItemDO.setAmountCompany(companyAmount);
                        if (SOC_ITEM_TYPE.equals(empSocItemDO.getItemType()) ||
                                ME_ITEM_TYPE.equals(empSocItemDO.getItemType())) {
                            personalSocAmount = personalSocAmount.add(personalAmount);
                            companySocAmount = companySocAmount.add(companyAmount);
                        } else {
                            //判断是公积金
                            personalPfAmount = personalPfAmount.add(personalAmount);
                            companyPfAmount = companyPfAmount.add(companyAmount);
                        }
                    } else {
                        if (bigDecimal.compareTo(empSocItemDO.getCardinalityDefault()) <= 0) {
                            continue;
                        }
                        BigDecimal hundred = new BigDecimal("0.01");
                        // 否则设置的是比例,这里需要用传进来的基数减去本来的基数,乘公司个人比例
                        // 判断是社保
                        BigDecimal personalAmount =
                                bigDecimal.subtract(empSocItemDO.getCardinalityDefault())
                                        .multiply(empSocItemDO.getPersentPersonal().multiply(hundred));
                        BigDecimal companyAmount =
                                bigDecimal.subtract(empSocItemDO.getCardinalityDefault())
                                        .multiply(empSocItemDO.getPersentCompany().multiply(hundred));
                        empSocItemDO.setAmountPersonal(personalAmount);
                        empSocItemDO.setAmountCompany(companyAmount);
                        if (SOC_ITEM_TYPE.equals(empSocItemDO.getItemType()) ||
                                ME_ITEM_TYPE.equals(empSocItemDO.getItemType())) {
                            personalSocAmount = personalSocAmount.add(personalAmount);
                            companySocAmount = companySocAmount.add(companyAmount);
                        } else {
                            //判断是公积金
                            personalPfAmount = personalPfAmount.add(personalAmount);
                            companyPfAmount = companyPfAmount.add(companyAmount);
                        }
                    }
                    empSocItemDO.setId(null);
                    empSocItemDO.setEmpSocId(id);
                    empSocItemDO.setCardinalityDefault(bigDecimal);
                    insertItemList.add(empSocItemDO);
                }
                if (companySocAmount.compareTo(BigDecimal.ZERO) == 0 &&
                        companyPfAmount.compareTo(BigDecimal.ZERO) == 0 &&
                        personalSocAmount.compareTo(BigDecimal.ZERO) == 0 &&
                        personalPfAmount.compareTo(BigDecimal.ZERO) == 0) {
                    continue;
                }
                empSocInfoDO.setCompanySocAmount(companySocAmount);
                empSocInfoDO.setCompanyPfAmount(companyPfAmount);
                empSocInfoDO.setPersonalSocAmount(personalSocAmount);
                empSocInfoDO.setPersonalPfAmount(personalPfAmount);
                empSocInfoService.save(empSocInfoDO, tokenUser.getSiteId(), tokenUser.getUserId());
                empSocItemDAO.insertListAndSetId(insertItemList);
            }

        }
        result.append(empSocMonthDO.getId());
        result.append("/");
        result.append(empSocMonthDO.getYear());
        result.append("/");
        result.append(empSocMonthDO.getMonth());
        if (fillSocQuery.getLastDt() != null) {
            fillDifferenceUpdate(fillSocQuery.getLastDt(), fillSocQuery.getSocProgId(), fillSocQuery.getCompanyId(),
                    itemNameCardinalityMap, fillSocQuery.getOnlySocAmount(), monthDifferences, tokenUser);
        }
        HrLogKit.logForSave("由管理员" + tokenUser.getUserName() + "进行社保补差",
                "EmpSocInfo", fillSocQuery.getCompanyId(), fillSocQuery.getCompanyId(), tokenUser);
        return result.toString();
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public void pfFillPayment(FillSocQuery fillSocQuery, TokenUser tokenUser) {
        Date fillPaymentStartDate = fillSocQuery.getFillPaymentStartDate();
        Date fillPaymentEndDate = fillSocQuery.getFillPaymentEndDate();
        String companyId = fillSocQuery.getCompanyId();
        SocProgDO socProgDO = socProgService.selectDOById(fillSocQuery.getSocProgId(), tokenUser.getSiteId());
        List<String> empIdList = fillSocQuery.getEmpIdList();
        ParamException.notEmpty(empIdList, "请选择补缴人员");
        Map<String, EmpInfoDO> empMap = empInfoService.selectDoByIds(empIdList)
                .stream().collect(Collectors.toMap(EmpInfoDO::getId, v -> v));
        // 拿到这个参保方案的公积金子项
        List<SocProgItemDO> empPfItemDOList = fillSocQuery.getEmpSocItemDOList();
        empPfItemDOList = empPfItemDOList.stream()
                .filter(socProgItemDO -> {
                    if ("缴费合计".equals(socProgItemDO.getItemName())) {
                        return false;
                    }
                    return PF_ITEM_TYPE.equals(socProgItemDO.getItemType());
                }).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(empPfItemDOList)) {
            throw new ParamException("方案" + socProgDO.getProgName() + "无公积金项,不可进行公积金补缴");
        }
        // 拿到公积金补缴的月份
        List<Date> monthDifferences = DateUtils.getMonthDifferences(fillPaymentStartDate, fillPaymentEndDate);
        // 计算每个月的补缴滞纳金 (平均)
        List<BigDecimal> fines = calculateFines(fillSocQuery.getFine(), monthDifferences.size());
        String currentMonthId = fillSocQuery.getMonthId();
        checkCostBillByMonthId(currentMonthId, fillSocQuery.getMonth(), tokenUser);
        // 每个人,每个月都要补缴一次
        List<EmpSocRelatedDO> empSocRelatedList = empSocRelatedService
                .selectByEmpIdList(empIdList, tokenUser.getSiteId());
        Map<String, EmpSocRelatedDO> relatedMap = empSocRelatedList.stream()
                .collect(Collectors.toMap(EmpSocRelatedDO::getEmpId, v -> v));
        for (String empId : empIdList) {
            EmpSocRelatedDO empSocRelated = relatedMap.get(empId);
            EmpInfoDO empInfoDO = empMap.get(empId);
            for (int i = 0; i < monthDifferences.size(); i++) {
                String[] yearAndMonth = DateUtils.getYearAndMonth(monthDifferences.get(i));
                String month = empSocMonthService.selectMonthIdByYearAndMonth(companyId,
                        yearAndMonth[0], yearAndMonth[1], tokenUser.getSiteId());
                // 判断是否有正常参保记录
                EmpSocInfoDO exitInfo = empSocInfoService.selectInfoByMonthId(empId, month, tokenUser);
                if (!ObjectUtils.isEmpty(exitInfo)) {
                    throw new ParamException("员工" + empInfoDO.getName() + yearAndMonth[1] + "月已参保不可补缴");
                }
                // 判断该月份是否存在补缴记录
                String empSocInfoId = empSocInfoService.selectEmpIsHaveFillCollect(SUPPLEMENT_TYPE_TWO, yearAndMonth[0],
                        yearAndMonth[1], empInfoDO.getId(), currentMonthId, companyId, tokenUser.getSiteId());
                ParamException.isFalse(StringKit.isNotBlank(empSocInfoId), "员工" + empInfoDO.getName() +
                        yearAndMonth[1] + "月存在补缴记录，请勿重复添加!");
                // 查询这个月有没有补收,有就加入,没有就新创建
                empSocInfoId = empSocInfoService.selectEmpIsHaveFillCollect(SUPPLEMENT_TYPE_ONE, yearAndMonth[0], yearAndMonth[1],
                        empInfoDO.getId(), currentMonthId, companyId, tokenUser.getSiteId());
                // 有,更新
                if (!StringUtils.isEmpty(empSocInfoId)) {
                    EmpSocInfoDO empSocInfoUpdate = empSocInfoService.selectDOById(empSocInfoId, tokenUser.getSiteId());
                    // 根据付款归属计算金额
                    gatherAmountByPayAttribution(socProgDO, empPfItemDOList, empSocInfoUpdate, fillSocQuery.getPayAttribution(), PF_ITEM_TYPE);
                    String supplementType = empSocInfoUpdate.getSupplementType() + SUPPLEMENT_TYPE_TWO;
                    empSocInfoUpdate.setSupplementType(supplementType);
                    empSocInfoUpdate.setAccumulationFundFine(fines.get(i));
                    empSocInfoUpdate.setServiceCost(empSocInfoUpdate.getServiceCost().add(fillSocQuery.getServiceCost()));
                    empSocInfoUpdate.setEmpSocStatus(empSocRelated.getSocState());
                    empSocInfoUpdate.setEmpMeStatus(empSocRelated.getMeState());
                    empSocInfoUpdate.setEmpPfStatus(empSocRelated.getPfState());
                    empSocInfoService.updateByIdSelective(empSocInfoUpdate, tokenUser.getSiteId(), tokenUser.getUserId());
                } else {
                    // 没有新创建
                    EmpSocInfoDO empSocInfoInsert = new EmpSocInfoDO();
                    empSocInfoInsert.setCompanyPfAmount(new BigDecimal("0"));
                    empSocInfoInsert.setPersonalPfAmount(new BigDecimal("0"));
                    // 根据付款归属计算金额
                    gatherAmountByPayAttribution(socProgDO, empPfItemDOList, empSocInfoInsert, fillSocQuery.getPayAttribution(), PF_ITEM_TYPE);
                    customEmpSocInfoDO(empSocInfoInsert, empInfoDO, currentMonthId, companyId,
                            socProgDO, yearAndMonth, fillSocQuery, SUPPLEMENT_TYPE_TWO, fines.get(i));
                    empSocInfoInsert.setEmpSocStatus(empSocRelated.getSocState());
                    empSocInfoInsert.setEmpMeStatus(empSocRelated.getMeState());
                    empSocInfoInsert.setEmpPfStatus(empSocRelated.getPfState());
                    EmpSocInfoDO EmpSocInfoDO = empSocInfoService.save(empSocInfoInsert, tokenUser.getSiteId(), tokenUser.getUserId());
                    empSocInfoId = EmpSocInfoDO.getId();
                }
                // 保存完参保管理记录,保存参保子项
                List<EmpSocItemDO> empSocItemDOS = new ArrayList<>();
                for (SocProgItemDO empSocItemDO : empPfItemDOList) {
                    EmpSocItemDO empSocItemDOInsert = new EmpSocItemDO();
                    BeanUtils.copyProperties(empSocItemDO, empSocItemDOInsert);
                    empSocItemDOInsert.setEmpSocId(empSocInfoId);
                    previewFillItemAmount(socProgDO, empSocItemDOInsert, empSocItemDO, fillSocQuery.getPayAttribution(), tokenUser);
                    empSocItemDOS.add(empSocItemDOInsert);
                }
                if (!CollectionUtils.isEmpty(empSocItemDOS)) {
                    empSocItemDAO.insertListAndSetId(empSocItemDOS);
                }

            }
            //用工档案
            String startDate = DateUtils.getYearMonthByDate(fillPaymentStartDate);
            String endDate = DateUtils.getYearMonthByDate(fillPaymentEndDate);
            String desc = "由管理员" + tokenUser.getUserName() + "办理公积金补缴,起始年月为" + startDate + ",终止年月为" + endDate +
                    "费用归属为" + SocPayAttribution.find(fillSocQuery.getPayAttribution()).getDesc();
            personalEventService.autoSave(empInfoDO.to(EmpInfoVO.class), tokenUser, desc,
                    PersonalEventEnum.FILL_PAYMENT.getValue(), PersonalEventEnum.FILL_PAYMENT.getDesc());
        }
        HrLogKit.logForSave("由管理员" + tokenUser.getUserName() + "进行公积金补缴",
                "EmpSocInfo", companyId, companyId, tokenUser);
    }


    private List<BigDecimal> calculateFines(BigDecimal fine, int size) {
        fine = fine == null ? new BigDecimal("0") : fine;
        List<BigDecimal> fines = new ArrayList<>();
        if (size == 0) {
            return fines;
        }
        if (size == 1) {
            fines.add(fine);
        }
        long value = fine.multiply(new BigDecimal(100)).longValue();
        long remainder = value % size;
        fines.add(new BigDecimal(value / size + remainder)
                .divide(new BigDecimal(100), 2, RoundingMode.UNNECESSARY));
        for (int i = 1; i < size; i++) {
            fines.add(new BigDecimal(value / size)
                    .divide(new BigDecimal(100), 2, RoundingMode.UNNECESSARY));
        }
        return fines;
    }

    @Override
    public List<SocFillPreviewVO> previewFill(PreviewFillQuery previewFillQuery, TokenUser tokenUser) {
        Date beginDate = previewFillQuery.getBeginDate();
        ParamException.notNull(beginDate, "起始时间不能为空");

        Date endDate = previewFillQuery.getEndDate();
        ParamException.notNull(endDate, "截止时间不能为空");

        String socProgId = previewFillQuery.getSocProgId();
        ParamException.notNull(socProgId, "参保方案Id不能为空");

        Integer type = previewFillQuery.getType();
        ParamException.notNull(type, "类型不能为空");

        Integer payAttribution = previewFillQuery.getPayAttribution();
        ParamException.notNull(type, "缴费所属不能为空");
        List<SocFillPreviewVO> socFillPreviewList = new ArrayList<>();
        List<Date> monthDifferences = DateUtils.getMonthDifferences(beginDate, endDate);
        SocProgDO socProgDO = socProgService.selectDOById(socProgId, tokenUser.getSiteId());
        for (Date monthDifference : monthDifferences) {
            List<SocProgItemDO> empSocItemDOList = previewFillQuery.getEmpSocItemDOList();
            empSocItemDOList = empSocItemDOList.stream()
                    .filter(socProgItemDO -> {
                        if ("缴费合计".equals(socProgItemDO.getItemName())) {
                            return false;
                        }
                        return type.equals(socProgItemDO.getItemType());
                    })
                    .collect(Collectors.toList());
            for (SocProgItemDO socProgItemDO : empSocItemDOList) {
                SocFillPreviewVO socFillPreviewVO = socProgItemDO.to(SocFillPreviewVO.class);
                if (socProgDO.getOnlySocAmount()) {
                    socFillPreviewVO.setCardinalityDefault(socProgItemDO.getCardinalityDefaultAmount());
                }
                socFillPreviewVO.setBelongsDate(monthDifference);
                previewFillAmount(socProgDO, socFillPreviewVO, socProgItemDO, payAttribution);
                socFillPreviewList.add(socFillPreviewVO);
            }

        }


        return socFillPreviewList;
    }

    @Override
    public SocProgCountAndNextMonthVO selectEmpCountWithSocProgId(String socProgId, String companyId, String siteId) {
        SocProgCountAndNextMonthVO socProgCountAndNextMonthVO = new SocProgCountAndNextMonthVO();
        Map<String, Date> dateList = empSocMonthService.selectMonthIdGreatThanYearAndMonth(companyId, siteId);
        socProgCountAndNextMonthVO.setDateList(dateList);
        socProgCountAndNextMonthVO.setEmpCount(empSocInfoService.selectEmpListWithSocProgId(socProgId, companyId, siteId).size());
        return socProgCountAndNextMonthVO;
    }

    @Override
    public String excelExport(EmpSocTransformQuery empSocTransformQuery, TokenUser tokenUser) {
        buildEmpSocListQuery(empSocTransformQuery);
        List<EmpSocTransformVO> dataList = empSocTransformDAO
                .selectEmpSocList(empSocTransformQuery, tokenUser.getSiteId());
        // 赋值最近一条参保记录的金额
        socListAmountInfo(dataList, empSocTransformQuery.getCompanyId(), tokenUser);
        return ExcelKit.exportExcel("emptySocList", "社保名单信息", SocListExportDTO.class, dataList);
    }

    @Override
    public String empSocInfoExport(EmpSocInfoQuery empSocInfoQuery, TokenUser tokenUser) {
        if (ObjectUtils.isEmpty(empSocInfoQuery.getTopStatus())) {
            empSocInfoQuery.setTopStatus(-1);
        }
        String monthId = empSocInfoQuery.getMonthId();
        CompanyDO companyDO = companyService.selectDOById(empSocInfoQuery.getCompanyId(), tokenUser.getSiteId());
        EmpSocMonthDO empSocMonthDO = empSocMonthService.selectDOById(monthId, tokenUser.getSiteId());
        List<EmpSocInfoListVO> empSocInfoListVOList = empSocInfoService
                .selectEmpSocInfoByExport(empSocInfoQuery, tokenUser.getSiteId());
        for (int i = 1; i <= empSocInfoListVOList.size(); i++) {
            EmpSocInfoListVO empSocInfoListVO = empSocInfoListVOList.get(i - 1);
            empSocInfoListVO.setIndex(i);
        }
        ParamException.notEmpty(empSocInfoListVOList, "没有需要导出的数据，请调整检索条件");
        List<FieldItemVO> headInfo = empSocInfoQuery.getHeadInfo();
        // 定义表头集合
        List<List<String>> headList = new ArrayList<>();
        // 记录一下当前用户的选择
        List<HeaderFieldsAddDTO> insertHeadList = new ArrayList<>();
        int sort = 1;
        for (FieldItemVO fieldItemVO : headInfo) {
            List<String> oneHead = new ArrayList<>();
            oneHead.add(fieldItemVO.getName());
            headList.add(oneHead);
            HeaderFieldsAddDTO insertHead = new HeaderFieldsAddDTO();
            insertHead.setFieldName(fieldItemVO.getName());
            insertHead.setFieldEnName(fieldItemVO.getEnName());
            insertHead.setModuleCode("empSocInfoExport");
            insertHead.setModuleType("参保管理导出");
            insertHead.setSubjectId(empSocInfoQuery.getCompanyId());
            insertHead.setSubjectType("company");
            insertHead.setFieldGroup("基础信息");
            insertHead.setIsOpen(true);
            insertHead.setIsEdit(true);
            insertHead.setIsFix(true);
            insertHead.setSort(sort++);
            insertHeadList.add(insertHead);
        }
        // 定义所有的数据集合
        List<List<String>> dataList = new ArrayList<>();
        HashSet<String> totalHeadSet = new HashSet<>();
        // 先for循环每条记录
        for (EmpSocInfoListVO empSocInfoListVO : empSocInfoListVOList) {
            List<EmpSocItemDO> empSocItemList = empSocItemService
                    .selectByEmpSocId(empSocInfoListVO.getId(), tokenUser.getSiteId());
            // 差额费用
            List<SocDifferenceDO> socDifferenceList = socDifferenceService
                    .selectBySocInfoIdList(Collections.singletonList(empSocInfoListVO.getId()), tokenUser.getSiteId());
            BigDecimal companyDifferenceAmount = new BigDecimal("0");
            BigDecimal personalDifferenceAmount = new BigDecimal("0");
            Map<String, EmpSocItemDO> itemMap = empSocItemList.stream()
                    .collect(Collectors.toMap(EmpSocItemDO::getItemName, v -> v));
            Map<String, SocDifferenceDO> differenceMap = new HashMap<>();
            if (!CollectionUtils.isEmpty(socDifferenceList)) {
                for (SocDifferenceDO socDifferenceDO : socDifferenceList) {
                    if (!ObjectUtils.isEmpty(socDifferenceDO.getCompanyDifference())) {
                        companyDifferenceAmount = companyDifferenceAmount.add(socDifferenceDO.getCompanyDifference());
                    }
                    if (!ObjectUtils.isEmpty(socDifferenceDO.getPersonalDifference())) {
                        personalDifferenceAmount = personalDifferenceAmount.add(socDifferenceDO.getPersonalDifference());
                    }
                }
                differenceMap = socDifferenceList.stream()
                        .collect(Collectors.toMap(SocDifferenceDO::getDifferenceName, v -> v));
            }
            BigDecimal differenceAmount = companyDifferenceAmount.add(personalDifferenceAmount);
            // 定义好每条数据的容器
            List<String> oneData = new ArrayList<>();
            // 在循环每个表头
            for (FieldItemVO fieldItemVO : headInfo) {
                String enName = fieldItemVO.getEnName();
                String headItem = fieldItemVO.getName();
                // 如果不是以extra开头说明是基本信息
                if (!enName.startsWith("extra")) {
                    oneData.add(enNameToDate2(enName, empSocInfoListVO, differenceAmount));
                    if (SERVICE_COST.equals(enName) || FINE.equals(enName) || AMOUNT.equals(enName)) {
                        totalHeadSet.add(headItem);
                    }
                } else {
                    int bracketIndex = headItem.indexOf("(");
                    // 表头是 个人(单位)缴纳比例/基数/金额(某某保险)的形式   需要把那个某某保险  给截取出来 并且找到对应的子项
                    String headItemName = headItem.substring(bracketIndex + 1, headItem.length() - 1);
                    EmpSocItemDO empSocItemDO = itemMap.get(headItemName);
                    if (!ObjectUtils.isEmpty(empSocItemDO)) {
                        if (enName.contains("Cardinality")) {
                            oneData.add(empSocItemDO.getCardinalityDefault().stripTrailingZeros().toPlainString());
                        } else if (enName.contains("CompanyProportion")) {
                            oneData.add(empSocItemDO.getPersentCompany().stripTrailingZeros().toPlainString() + "%");
                        } else if (enName.contains("PersonalProportion")) {
                            oneData.add(empSocItemDO.getPersentPersonal().stripTrailingZeros().toPlainString() + "%");
                        } else if (enName.contains("CompanyAmount")) {
                            oneData.add(empSocItemDO.getAmountCompany().stripTrailingZeros().toPlainString());
                            totalHeadSet.add(headItem);
                        } else if (enName.contains("PersonalAmount")) {
                            oneData.add(empSocItemDO.getAmountPersonal().stripTrailingZeros().toPlainString());
                            totalHeadSet.add(headItem);
                        }
                    } else {
                        // 如果不是参保子项  有可能是合计  和  差额缴费
                        //再区分一下合计和 差额费用
                        String differenceName;
                        if (bracketIndex != -1) {
                            differenceName = headItem.substring(0, bracketIndex);
                        } else {
                            differenceName = headItem;
                        }
                        SocDifferenceDO socDifferenceDO = differenceMap.get(differenceName);
                        if (!ObjectUtils.isEmpty(socDifferenceDO)) {
                            if (enName.contains("DifferenceCompanyAmount")) {
                                oneData.add(socDifferenceDO.getCompanyDifference().stripTrailingZeros().toPlainString());
                                totalHeadSet.add(headItem);
                            } else if (enName.contains("DifferencePersonalAmount")) {
                                oneData.add(socDifferenceDO.getPersonalDifference().stripTrailingZeros().toPlainString());
                                totalHeadSet.add(headItem);
                            }
                        } else {
                            if (enName.contains("CompanySocTotal")) {
                                oneData.add(empSocInfoListVO.getCompanySocAmount().stripTrailingZeros().toPlainString());
                                totalHeadSet.add(headItem);
                            } else if (enName.contains("CompanyPfTotal")) {
                                oneData.add(empSocInfoListVO.getCompanyPfAmount().stripTrailingZeros().toPlainString());
                                totalHeadSet.add(headItem);
                            } else if (enName.contains("CompanyTotal")) {
                                oneData.add(empSocInfoListVO.getCompanyPfAmount().add(empSocInfoListVO.getCompanySocAmount())
                                        .stripTrailingZeros().toPlainString());
                                totalHeadSet.add(headItem);
                            } else if (enName.contains("CompanyAllTotal")) {
                                oneData.add(empSocInfoListVO.getCompanyPfAmount()
                                        .add(empSocInfoListVO.getCompanySocAmount().add(companyDifferenceAmount))
                                        .stripTrailingZeros().toPlainString());
                                totalHeadSet.add(headItem);
                            } else if (enName.contains("PersonalSocTotal")) {
                                oneData.add(empSocInfoListVO.getPersonalSocAmount().stripTrailingZeros().toPlainString());
                                totalHeadSet.add(headItem);
                            } else if (enName.contains("PersonalPfTotal")) {
                                oneData.add(empSocInfoListVO.getPersonalPfAmount().stripTrailingZeros().toPlainString());
                                totalHeadSet.add(headItem);
                            } else if (enName.contains("PersonalTotal")) {
                                oneData.add(empSocInfoListVO.getPersonalPfAmount().add(empSocInfoListVO.getPersonalSocAmount())
                                        .stripTrailingZeros().toPlainString());
                                totalHeadSet.add(headItem);
                            } else if (enName.contains("PersonalAllTotal")) {
                                oneData.add(empSocInfoListVO.getPersonalPfAmount()
                                        .add(empSocInfoListVO.getPersonalSocAmount().add(personalDifferenceAmount))
                                        .stripTrailingZeros().toPlainString());
                                totalHeadSet.add(headItem);
                            } else {
                                oneData.add(null);
                            }
                        }
                    }
                }
            }
            dataList.add(oneData);
        }

        // 最后保存一下当前用户选的导出的表头(就是删了再存一下)
        adminProviderService.deleteByModuleCodeAndUser(empSocInfoQuery.getCompanyId(), "empSocInfoExport", tokenUser);
        adminProviderService.bachSaveHeaderFields(insertHeadList, tokenUser);
        return ExcelKit.writeExcelTotalAndNotTemplate("emptySocInfo", dataList, headList,
                companyDO.getName() + "_" + empSocMonthDO.getMonth() + "月", totalHeadSet);
    }

    @Override
    public String empSocDetailsExport(String companyId, String empId, List<String> empSocInfoIdList, TokenUser tokenUser) {
        List<EmpSocDetailsExportVO> empSocDetailsExportList = new ArrayList<>();
        EmpSocTransformQuery empSocTransformQuery = new EmpSocTransformQuery();
        empSocTransformQuery.setCompanyId(companyId);
        empSocTransformQuery.setEmpId(empId);
        if (!CollectionUtils.isEmpty(empSocInfoIdList)) {
            empSocTransformQuery.setEmpSocInfoIdList(empSocInfoIdList);
        }
        List<EmpSocTransformVO> empSocTransformVOList = empSocTransformDAO.selectEmpSocInfoByEmpId(empSocTransformQuery, tokenUser.getSiteId());
        for (EmpSocTransformVO empSocTransformVO : empSocTransformVOList) {
            EmpSocDetailsExportVO empSocDetailsExportVO = empSocTransformVO.to(EmpSocDetailsExportVO.class);
            empSocDetailsExportVO.setSocDate(empSocTransformVO.getYear() + "-" + empSocTransformVO.getMonth());
            if (empSocTransformVO.getPayCostType() != null) {
                empSocDetailsExportVO.setPayCostType(SocPayCostType.find(empSocTransformVO.getPayCostType()).getDesc());
            } else {
                empSocDetailsExportVO.setPayCostType("此月减员");
            }

            empSocDetailsExportList.add(empSocDetailsExportVO);
        }
        return ExcelKit.exportExcel("empSocDetails", "社保个人详情", EmpSocDetailsExportVO.class, empSocDetailsExportList);
    }

    @Override
    public List<FieldItemGroupVO> selectAllHead(String companyId, String monthId, TokenUser tokenUser) {
        List<HeaderFieldsTemplateDO> headerBasic = new ArrayList<>();
        List<EmpSocInfoDO> empSocInfoDOList;
        Map<String, Integer> selectHead;
        // 如果monthId不为空说明头信息为参保管理
        if (!StringUtils.isEmpty(monthId)) {
            // 查询出这个参保月的所有参保信息
            empSocInfoDOList = empSocInfoService.selectEmpInfoByMonthId(companyId, monthId, tokenUser);
            selectHead = exportBasicAndSelectItem(headerBasic, "empSocInfoExport", companyId, tokenUser);
        } else {
            // 否则为社保名单
            // 查询出这个公司所有参保记录
            empSocInfoDOList = empSocInfoService.selectInfoByCompanyId(companyId, tokenUser.getSiteId());
            selectHead = exportBasicAndSelectItem(headerBasic, "empSocListExport", companyId, tokenUser);
        }
        if (CollectionUtils.isEmpty(empSocInfoDOList)) {
            throw new ParamException("无数据需要导出");
        }
        List<FieldItemGroupVO> fieldItemGroupVOList = new ArrayList<>();
        //基础信息的属性组
        FieldItemGroupVO fieldItemGroupBasic = new FieldItemGroupVO();
        fieldItemGroupBasic.setGroupName("基础信息");
        List<FieldItemVO> fieldItemBasicList = new ArrayList<>();
        for (HeaderFieldsTemplateDO basicItemTemplate : headerBasic) {
            FieldItemVO basicItem = new FieldItemVO();
            basicItem.setName(basicItemTemplate.getName());
            basicItem.setEnName(basicItemTemplate.getCode());
            basicItem.setIsSelect(selectHead.containsKey(basicItemTemplate.getName()));
            basicItem.setSort(basicItem.getIsSelect() ? selectHead.get(basicItem.getName()) : 0);
            fieldItemBasicList.add(basicItem);
        }
        fieldItemGroupBasic.setGroupItem(fieldItemBasicList);
        //缴纳基数
        FieldItemGroupVO cardinalityGroup = new FieldItemGroupVO();
        cardinalityGroup.setGroupName("缴纳基数");
        List<FieldItemVO> cardinalityGroupList = new ArrayList<>();
        // 单位缴纳比例
        FieldItemGroupVO companyProportionGroup = new FieldItemGroupVO();
        companyProportionGroup.setGroupName("单位缴纳比例");
        List<FieldItemVO> companyProportionGroupList = new ArrayList<>();
        // 个人缴纳比例
        FieldItemGroupVO personalProportionGroup = new FieldItemGroupVO();
        personalProportionGroup.setGroupName("个人缴纳比例");
        List<FieldItemVO> personalProportionGroupList = new ArrayList<>();
        // 单位缴纳金额
        FieldItemGroupVO companyAmountGroup = new FieldItemGroupVO();
        companyAmountGroup.setGroupName("单位缴纳金额");
        List<FieldItemVO> companyAmountGroupList = new ArrayList<>();
        // 个人缴纳金额
        FieldItemGroupVO personalAmountGroup = new FieldItemGroupVO();
        personalAmountGroup.setGroupName("个人缴纳金额");
        List<FieldItemVO> personalAmountGroupList = new ArrayList<>();
        // 缴费合计
        FieldItemGroupVO totalAmountGroup = new FieldItemGroupVO();
        totalAmountGroup.setGroupName("缴费合计");
        List<FieldItemVO> totalAmountGroupList = new ArrayList<>();
        // 填充子项表头
        List<String> empSocInfoIdList = empSocInfoDOList.stream().map(EmpSocInfoDO::getId).collect(Collectors.toList());
        List<EmpSocItemDO> empSocItemList = empSocItemService.selectByEmpSocIdList(empSocInfoIdList, tokenUser.getSiteId());
        List<String> itemNameList = empSocItemList.stream()
                .map(EmpSocItemDO::getItemName).distinct().collect(Collectors.toList());
        for (String itemName : itemNameList) {
            FieldItemVO cardinalityItem = new FieldItemVO();
            cardinalityItem.setName("缴纳基数(" + itemName + ")");
            cardinalityItem.setEnName("extraCardinality" +
                    UUID.randomUUID().toString().replace("-", ""));
            cardinalityItem.setIsSelect(selectHead.containsKey(cardinalityItem.getName()));
            cardinalityItem.setSort(cardinalityItem.getIsSelect() ? selectHead.get(cardinalityItem.getName()) : 0);
            cardinalityGroupList.add(cardinalityItem);

            FieldItemVO companyProportionItem = new FieldItemVO();
            companyProportionItem.setName("单位缴纳比例(" + itemName + ")");
            companyProportionItem.setEnName("extraCompanyProportion" +
                    UUID.randomUUID().toString().replace("-", ""));
            companyProportionItem.setIsSelect(selectHead.containsKey(companyProportionItem.getName()));
            companyProportionItem.setSort(companyProportionItem.getIsSelect() ? selectHead.get(companyProportionItem.getName()) : 0);
            companyProportionGroupList.add(companyProportionItem);

            FieldItemVO personalProportionItem = new FieldItemVO();
            personalProportionItem.setName("个人缴纳比例(" + itemName + ")");
            personalProportionItem.setEnName("extraPersonalProportion" +
                    UUID.randomUUID().toString().replace("-", ""));
            personalProportionItem.setIsSelect(selectHead.containsKey(personalProportionItem.getName()));
            personalProportionItem.setSort(personalProportionItem.getIsSelect() ? selectHead.get(personalProportionItem.getName()) : 0);
            personalProportionGroupList.add(personalProportionItem);

            FieldItemVO companyAmountItem = new FieldItemVO();
            companyAmountItem.setName("单位缴纳金额(" + itemName + ")");
            companyAmountItem.setEnName("extraCompanyAmount" +
                    UUID.randomUUID().toString().replace("-", ""));
            companyAmountItem.setIsSelect(selectHead.containsKey(companyAmountItem.getName()));
            companyAmountItem.setSort(companyAmountItem.getIsSelect() ? selectHead.get(companyAmountItem.getName()) : 0);
            companyAmountGroupList.add(companyAmountItem);

            FieldItemVO personalAmountItem = new FieldItemVO();
            personalAmountItem.setName("个人缴纳金额(" + itemName + ")");
            personalAmountItem.setEnName("extraPersonalAmount" +
                    UUID.randomUUID().toString().replace("-", ""));
            personalAmountItem.setIsSelect(selectHead.containsKey(personalAmountItem.getName()));
            personalAmountItem.setSort(personalAmountItem.getIsSelect() ? selectHead.get(personalAmountItem.getName()) : 0);
            personalAmountGroupList.add(personalAmountItem);
        }
        // 填充差额费用表头
        List<SocDifferenceDO> socDifferenceList = socDifferenceService
                .selectBySocInfoIdList(empSocInfoIdList, tokenUser.getSiteId());
        if (!CollectionUtils.isEmpty(socDifferenceList)) {
            Map<String, List<SocDifferenceDO>> differenceNameMap = socDifferenceList
                    .stream().collect(Collectors.groupingBy(SocDifferenceDO::getDifferenceName));
            List<String> differenceNameList = socDifferenceList.stream()
                    .map(SocDifferenceDO::getDifferenceName).distinct().collect(Collectors.toList());
            for (String differenceName : differenceNameList) {
                List<SocDifferenceDO> existSocDifferenceList = differenceNameMap.get(differenceName);
                List<BigDecimal> companyDifferenceList = existSocDifferenceList.stream()
                        .map(SocDifferenceDO::getCompanyDifference).distinct().collect(Collectors.toList());
                List<BigDecimal> personalDifferenceList = existSocDifferenceList.stream()
                        .map(SocDifferenceDO::getPersonalDifference).distinct().collect(Collectors.toList());
                if (!(companyDifferenceList.size() == 1 && companyDifferenceList.get(0).compareTo(BigDecimal.ZERO) == 0)) {
                    FieldItemVO companyAmountItem = new FieldItemVO();
                    companyAmountItem.setName(differenceName + "(单位)");
                    companyAmountItem.setEnName("extraDifferenceCompanyAmount" +
                            UUID.randomUUID().toString().replace("-", ""));
                    companyAmountItem.setIsSelect(selectHead.containsKey(companyAmountItem.getName()));
                    companyAmountItem.setSort(companyAmountItem.getIsSelect() ? selectHead.get(companyAmountItem.getName()) : 0);
                    companyAmountGroupList.add(companyAmountItem);
                }
                if (!(personalDifferenceList.size() == 1 && personalDifferenceList.get(0).compareTo(BigDecimal.ZERO) == 0)) {
                    FieldItemVO personalAmountItem = new FieldItemVO();
                    personalAmountItem.setName(differenceName + "(个人)");
                    personalAmountItem.setEnName("extraDifferencePersonalAmount" +
                            UUID.randomUUID().toString().replace("-", ""));
                    personalAmountItem.setIsSelect(selectHead.containsKey(personalAmountItem.getName()));
                    personalAmountItem.setSort(personalAmountItem.getIsSelect() ? selectHead.get(personalAmountItem.getName()) : 0);
                    personalAmountGroupList.add(personalAmountItem);
                }
            }
        }
        // 合计
        FieldItemVO companySocTotalItem = new FieldItemVO();
        companySocTotalItem.setName("单位社保合计");
        companySocTotalItem.setEnName("extraCompanySocTotal");
        companySocTotalItem.setIsSelect(selectHead.containsKey(companySocTotalItem.getName()));
        companySocTotalItem.setSort(companySocTotalItem.getIsSelect() ? selectHead.get(companySocTotalItem.getName()) : 0);
        companyAmountGroupList.add(companySocTotalItem);

        FieldItemVO companyPfTotalItem = new FieldItemVO();
        companyPfTotalItem.setName("单位公积金合计");
        companyPfTotalItem.setEnName("extraCompanyPfTotal");
        companyPfTotalItem.setIsSelect(selectHead.containsKey(companyPfTotalItem.getName()));
        companyPfTotalItem.setSort(companyPfTotalItem.getIsSelect() ? selectHead.get(companyPfTotalItem.getName()) : 0);
        companyAmountGroupList.add(companyPfTotalItem);

        FieldItemVO companyTotalItem = new FieldItemVO();
        companyTotalItem.setName("单位社保公积金合计");
        companyTotalItem.setEnName("extraCompanyTotal");
        companyTotalItem.setIsSelect(selectHead.containsKey(companyTotalItem.getName()));
        companyTotalItem.setSort(companyTotalItem.getIsSelect() ? selectHead.get(companyTotalItem.getName()) : 0);
        companyAmountGroupList.add(companyTotalItem);

        FieldItemVO companyAllTotalItem = new FieldItemVO();
        companyAllTotalItem.setName("单位缴费合计");
        companyAllTotalItem.setEnName("extraCompanyAllTotal");
        companyAllTotalItem.setIsSelect(selectHead.containsKey(companyAllTotalItem.getName()));
        companyAllTotalItem.setSort(companyAllTotalItem.getIsSelect() ? selectHead.get(companyAllTotalItem.getName()) : 0);
        companyAmountGroupList.add(companyAllTotalItem);

        FieldItemVO personalSocTotalItem = new FieldItemVO();
        personalSocTotalItem.setName("个人社保合计");
        personalSocTotalItem.setEnName("extraPersonalSocTotal");
        personalSocTotalItem.setIsSelect(selectHead.containsKey(personalSocTotalItem.getName()));
        personalSocTotalItem.setSort(personalSocTotalItem.getIsSelect() ? selectHead.get(personalSocTotalItem.getName()) : 0);
        personalAmountGroupList.add(personalSocTotalItem);

        FieldItemVO personalPfTotalItem = new FieldItemVO();
        personalPfTotalItem.setName("个人公积金合计");
        personalPfTotalItem.setEnName("extraPersonalPfTotal");
        personalPfTotalItem.setIsSelect(selectHead.containsKey(personalPfTotalItem.getName()));
        personalPfTotalItem.setSort(personalPfTotalItem.getIsSelect() ? selectHead.get(personalPfTotalItem.getName()) : 0);
        personalAmountGroupList.add(personalPfTotalItem);

        FieldItemVO personalTotalItem = new FieldItemVO();
        personalTotalItem.setName("个人社保公积金合计");
        personalTotalItem.setEnName("extraPersonalTotal");
        personalTotalItem.setIsSelect(selectHead.containsKey(personalTotalItem.getName()));
        personalTotalItem.setSort(personalTotalItem.getIsSelect() ? selectHead.get(personalTotalItem.getName()) : 0);
        personalAmountGroupList.add(personalTotalItem);

        FieldItemVO personalAllTotalItem = new FieldItemVO();
        personalAllTotalItem.setName("个人缴费合计");
        personalAllTotalItem.setEnName("extraPersonalAllTotal");
        personalAllTotalItem.setIsSelect(selectHead.containsKey(personalAllTotalItem.getName()));
        personalAllTotalItem.setSort(personalAllTotalItem.getIsSelect() ? selectHead.get(personalAllTotalItem.getName()) : 0);
        personalAmountGroupList.add(personalAllTotalItem);

        // 总缴费
        FieldItemVO fieldItemAmount = new FieldItemVO();
        fieldItemAmount.setName("总缴费(含服务费)");
        fieldItemAmount.setEnName("amount");
        fieldItemAmount.setIsSelect(selectHead.containsKey(fieldItemAmount.getName()));
        fieldItemAmount.setSort(fieldItemAmount.getIsSelect() ? selectHead.get(fieldItemAmount.getName()) : 0);
        totalAmountGroupList.add(fieldItemAmount);

        fieldItemGroupVOList.add(fieldItemGroupBasic);
        cardinalityGroup.setGroupItem(cardinalityGroupList);
        fieldItemGroupVOList.add(cardinalityGroup);
        companyProportionGroup.setGroupItem(companyProportionGroupList);
        fieldItemGroupVOList.add(companyProportionGroup);
        personalProportionGroup.setGroupItem(personalProportionGroupList);
        fieldItemGroupVOList.add(personalProportionGroup);
        companyAmountGroup.setGroupItem(companyAmountGroupList);
        fieldItemGroupVOList.add(companyAmountGroup);
        personalAmountGroup.setGroupItem(personalAmountGroupList);
        fieldItemGroupVOList.add(personalAmountGroup);
        totalAmountGroup.setGroupItem(totalAmountGroupList);
        fieldItemGroupVOList.add(totalAmountGroup);
        return fieldItemGroupVOList;
    }

    @Override
    public Page<EmpSocTransformVO> selectEmpSocInfoByEmpId(EmpSocTransformQuery empSocTransformQuery, TokenUser tokenUser) {
        PageInfo<EmpSocTransformVO> empSocInfoByEmpIdPageInfo =
                PageHelper.startPage(empSocTransformQuery.getPageNo(), empSocTransformQuery.getPageSize()).doSelectPageInfo(() ->
                        empSocTransformDAO.selectEmpSocInfoByEmpId(empSocTransformQuery, tokenUser.getSiteId()));
        if (CollectionUtils.isEmpty(empSocInfoByEmpIdPageInfo.getList())) {
            return new Page<>(empSocTransformQuery.getPageSize(), empSocTransformQuery.getPageNo());
        }
        Page<EmpSocTransformVO> empSocInfoByEmpIdPage = new Page<>(empSocInfoByEmpIdPageInfo.getList(), empSocTransformQuery.getPageNo(),
                empSocTransformQuery.getPageSize(), (int) empSocInfoByEmpIdPageInfo.getTotal());
        //这个时候查出来的详情是没有子项详情,需要再把详情赋一下值
        for (EmpSocTransformVO empSocTransformVO : empSocInfoByEmpIdPage.getEntities()) {
            List<EmpSocItemDO> empSocItemDOList = empSocItemService.
                    selectEmpSocItemByInfoId(empSocTransformVO.getEmpSocInfoId(), tokenUser.getSiteId());
            empSocTransformVO.setEmpSocItemVOList(empSocItemDOList);
        }
        return empSocInfoByEmpIdPage;
    }

    @Override
    public EmpSocBrieflyVO selectEmpSocBriefly(String empId, TokenUser tokenUser) {
        EmpInfoDO empInfoDO = empInfoService.selectDOByIdIgnoreValid(empId);
        EmpSocBrieflyVO empSocBrieflyVO = empInfoDO.to(EmpSocBrieflyVO.class);
        EmpSocRelatedDO empSocRelatedDO = empSocRelatedService.selectByEmpIdIgnoreValid(empId, tokenUser.getSiteId());
        empSocBrieflyVO.setEmpSocStatus(empSocRelatedDO.getSocState());
        empSocBrieflyVO.setEmpMeStatus(empSocRelatedDO.getMeState());
        empSocBrieflyVO.setEmpPfStatus(empSocRelatedDO.getPfState());
        SocProgDO socProgDO = socProgService.selectDOById(empSocRelatedDO.getSchemeId(), tokenUser.getSiteId());
        if (!ObjectUtils.isEmpty(socProgDO)) {
            empSocBrieflyVO.setSocProgName(socProgDO.getProgName());
            empSocBrieflyVO.setSocCityName(socProgDO.getSocCityName());
        }
        List<EmpSocPlanDO> successPlanByEmp = empSocPlanService.getSuccessPlanByEmp(empId, tokenUser);
        if (!CollectionUtils.isEmpty(successPlanByEmp)) {
            empSocBrieflyVO.setSocDate(DateKit8.parseDate(successPlanByEmp.get(0).getYear() + "-" +
                    successPlanByEmp.get(0).getMonth() + "-01"));
        }
        return empSocBrieflyVO;
    }

    @Override
    public EmpSocTransformCountVO selectEmpSocCount(EmpSocInfoQuery empSocInfoQuery, TokenUser tokenUser) {
        String companyId = empSocInfoQuery.getCompanyId();
        // 拿到这个monthId
        EmpSocMonthDO empSocMonth = empSocMonthService.selectMonthByYearAndMonth(companyId, empSocInfoQuery.getYear(),
                empSocInfoQuery.getMonth(), tokenUser.getSiteId());
        ParamException.notNull(empSocMonth, "参保月不存在或已删除");
        String monthId = empSocMonth.getId();
        empSocInfoQuery.setCompanyId(empSocInfoQuery.getCompanyId());
        empSocInfoQuery.setMonthId(monthId);
        if (!StringUtils.isEmpty(empSocInfoQuery.getSocProgId())) {
            empSocInfoQuery.setProgId(empSocInfoQuery.getSocProgId());
        }
        List<EmpSocInfoListVO> empSocInfoListVOList = empSocInfoDAO.empSocInfoCount(empSocInfoQuery, tokenUser.getSiteId());
        EmpSocTransformCountVO empSocTransformCountVO = new EmpSocTransformCountVO();
        // 差额费用记录
        List<SocDifferenceDO> socDifferenceList = socDifferenceService.selectByMonthId(monthId, tokenUser);
        BigDecimal companyDifferenceAmount = new BigDecimal("0");
        BigDecimal personalDifferenceAmount = new BigDecimal("0");
        for (SocDifferenceDO socDifferenceDO : socDifferenceList) {
            if (!ObjectUtils.isEmpty(socDifferenceDO.getCompanyDifference())) {
                companyDifferenceAmount = companyDifferenceAmount.add(socDifferenceDO.getCompanyDifference());
            }
            if (!ObjectUtils.isEmpty(socDifferenceDO.getPersonalDifference())) {
                personalDifferenceAmount = personalDifferenceAmount.add(socDifferenceDO.getPersonalDifference());
            }
        }
        empSocTransformCountVO.setCompanyDifferenceAmount(companyDifferenceAmount);
        empSocTransformCountVO.setPersonalDifferenceAmount(personalDifferenceAmount);
        // 计算金额
        BigDecimal personalSocAmount = new BigDecimal("0");
        BigDecimal personalPfAmount = new BigDecimal("0");
        BigDecimal companySocAmount = new BigDecimal("0");
        BigDecimal companyPfAmount = new BigDecimal("0");
        BigDecimal socialSecurityFine = new BigDecimal("0");
        BigDecimal accumulationFundFine = new BigDecimal("0");
        BigDecimal serviceCost = new BigDecimal("0");
        Integer increaseCount = 0;
        Integer decreaseCount = 0;
        Integer normalSocCount = 0;
        // 在保人数 (正常参保+增员) 如果既有正常参保和增员算一人
        Integer inInsuranceCount = 0;
        List<String> inInsuranceEmp = new ArrayList<>();
        List<String> normalSocEmp = new ArrayList<>();
        List<String> increaseEmp = new ArrayList<>();
        List<String> decreaseEmp = new ArrayList<>();
        for (EmpSocInfoListVO empSocInfoListVO : empSocInfoListVOList) {
            List<Integer> statusList = Arrays.asList(empSocInfoListVO.getEmpSocStatus(),
                    empSocInfoListVO.getEmpMeStatus(), empSocInfoListVO.getEmpPfStatus());
            if (statusList.contains(NORMAL_SOC.getValue()) || statusList.contains(INCREMENT.getValue())) {
                if (!inInsuranceEmp.contains(empSocInfoListVO.getEmpId())) {
                    inInsuranceCount++;
                    inInsuranceEmp.add(empSocInfoListVO.getEmpId());
                }
            }
            if (statusList.contains(NORMAL_SOC.getValue())) {
                if (!normalSocEmp.contains(empSocInfoListVO.getEmpId())) {
                    normalSocCount++;
                    normalSocEmp.add(empSocInfoListVO.getEmpId());
                }
            }
            if (statusList.contains(INCREMENT.getValue())) {
                if (!increaseEmp.contains(empSocInfoListVO.getEmpId())) {
                    increaseCount++;
                    increaseEmp.add(empSocInfoListVO.getEmpId());
                }
            }
            if (statusList.contains(ATTRITION.getValue())) {
                if (!decreaseEmp.contains(empSocInfoListVO.getEmpId())) {
                    decreaseCount++;
                    decreaseEmp.add(empSocInfoListVO.getEmpId());
                }
            }
            personalSocAmount = personalSocAmount.add(empSocInfoListVO.getPersonalSocAmount());
            personalPfAmount = personalPfAmount.add(empSocInfoListVO.getPersonalPfAmount());
            companySocAmount = companySocAmount.add(empSocInfoListVO.getCompanySocAmount());
            companyPfAmount = companyPfAmount.add(empSocInfoListVO.getCompanyPfAmount());
            socialSecurityFine = socialSecurityFine.add(empSocInfoListVO.getSocialSecurityFine() == null ?
                    new BigDecimal(0) : empSocInfoListVO.getSocialSecurityFine());
            accumulationFundFine = accumulationFundFine.add(empSocInfoListVO.getAccumulationFundFine() == null ?
                    new BigDecimal(0) : empSocInfoListVO.getAccumulationFundFine());
            serviceCost = serviceCost.add(empSocInfoListVO.getServiceCost() == null ?
                    new BigDecimal(0) : empSocInfoListVO.getServiceCost());
        }
        empSocTransformCountVO.setPersonalSocAmount(personalSocAmount);
        empSocTransformCountVO.setPersonalPfAmount(personalPfAmount);
        empSocTransformCountVO.setCompanySocAmount(companySocAmount);
        empSocTransformCountVO.setCompanyPfAmount(companyPfAmount);
        empSocTransformCountVO.setSocialSecurityFine(socialSecurityFine);
        empSocTransformCountVO.setAccumulationFundFine(accumulationFundFine);
        empSocTransformCountVO.setServiceCost(serviceCost);
        empSocTransformCountVO.setAllAmount(personalSocAmount.add(personalPfAmount).add(companySocAmount)
                .add(companyPfAmount).add(socialSecurityFine).add(accumulationFundFine).add(serviceCost)
                .add(companyDifferenceAmount).add(personalDifferenceAmount));
        empSocTransformCountVO.setAllCount(inInsuranceCount);
        empSocTransformCountVO.setIncreaseCount(increaseCount);
        empSocTransformCountVO.setDecreaseCount(decreaseCount);
        empSocTransformCountVO.setNormalSocCount(normalSocCount);
        return empSocTransformCountVO;
    }

    @Override
    public EmpSocTransformCountVO selectEmpSocListCount(String companyId, TokenUser tokenUser) {
        EmpSocTransformQuery empSocTransformQuery = new EmpSocTransformQuery();
        empSocTransformQuery.setCompanyId(companyId);
        List<EmpSocTransformVO> empSocTransformVOList = empSocTransformDAO.selectEmpSocList(empSocTransformQuery, tokenUser.getSiteId());
        if (CollectionUtils.isEmpty(empSocTransformVOList)) {
            return new EmpSocTransformCountVO();
        }
        long notSocCount = 0L;
        int normalSocCount = 0;
        int increaseCount = 0;
        long waitIncreaseCount = 0L;
        int decreaseCount = 0;
        long waitDecreaseCount = 0L;
        long stopSocCount = 0L;
        EmpSocTransformCountVO empSocTransformCountVO = new EmpSocTransformCountVO();
        for (EmpSocTransformVO empSocTransformVO : empSocTransformVOList) {
            Integer meStatus = empSocTransformVO.getEmpMeStatus();
            Integer socStatus = empSocTransformVO.getEmpSocStatus();
            Integer pfStatus = empSocTransformVO.getEmpPfStatus();
            if (0 == meStatus || 0 == socStatus || 0 == pfStatus) {
                notSocCount += 1;
            }
            if (1 == meStatus || 1 == socStatus || 1 == pfStatus) {
                normalSocCount += 1;
            }
            if (2 == meStatus || 2 == socStatus || 2 == pfStatus) {
                increaseCount += 1;
            }
            if (3 == meStatus || 3 == socStatus || 3 == pfStatus) {
                waitIncreaseCount += 1;
            }
            if (4 == meStatus || 4 == socStatus || 4 == pfStatus) {
                decreaseCount += 1;
            }
            if (5 == meStatus || 5 == socStatus || 5 == pfStatus) {
                waitDecreaseCount += 1;
            }
            if (6 == meStatus || 6 == socStatus || 6 == pfStatus) {
                stopSocCount += 1;
            }
        }
        empSocTransformCountVO.setNotSocCount(notSocCount);
        empSocTransformCountVO.setNormalSocCount(normalSocCount);
        empSocTransformCountVO.setIncreaseCount(increaseCount);
        empSocTransformCountVO.setWaitIncreaseCount(waitIncreaseCount);
        empSocTransformCountVO.setDecreaseCount(decreaseCount);
        empSocTransformCountVO.setWaitDecreaseCount(waitDecreaseCount);
        empSocTransformCountVO.setStopSocCount(stopSocCount);
        empSocTransformCountVO.setAllCount(empSocTransformVOList.size());
        return empSocTransformCountVO;
    }

    @Override
    public Map<String, Integer> selectAllMantissaProcessingType() {
        Map<String, Integer> allMantissaProcessingTypeMap = new HashMap<>(16);
        MantissaProcessingType[] allMantissaProcessingTypeArray = MantissaProcessingType.values();
        for (MantissaProcessingType mantissaProcessingType : allMantissaProcessingTypeArray) {
            allMantissaProcessingTypeMap.put(mantissaProcessingType.getDesc(), mantissaProcessingType.getValue());
        }
        return allMantissaProcessingTypeMap;
    }

    @Override
    public EmpSocTransformCountVO selectEmpSocInfoByEmpIdCount(String companyId, String empId, TokenUser tokenUser) {
        EmpSocTransformCountVO empSocTransformCountVO = new EmpSocTransformCountVO();
        BigDecimal personalSocAmount = new BigDecimal("0");
        BigDecimal personalPfAmount = new BigDecimal("0");
        BigDecimal companySocAmount = new BigDecimal("0");
        BigDecimal companyPfAmount = new BigDecimal("0");
        BigDecimal allAmount = new BigDecimal("0");
        EmpSocTransformQuery empSocTransformQuery = new EmpSocTransformQuery();
        empSocTransformQuery.setCompanyId(companyId);
        empSocTransformQuery.setEmpId(empId);
        List<EmpSocTransformVO> empSocTransformVOList = empSocTransformDAO.selectEmpSocInfoByEmpId(empSocTransformQuery, tokenUser.getSiteId());
        for (EmpSocTransformVO empSocTransformVO : empSocTransformVOList) {
            personalSocAmount = personalSocAmount.add(empSocTransformVO.getPersonalSocAmount());
            personalPfAmount = personalPfAmount.add(empSocTransformVO.getPersonalPfAmount());
            companySocAmount = companySocAmount.add(empSocTransformVO.getCompanySocAmount());
            companyPfAmount = companyPfAmount.add(empSocTransformVO.getCompanyPfAmount());
            allAmount = allAmount.add(empSocTransformVO.getSocAmount().add(empSocTransformVO.getPfAmount()));
        }
        empSocTransformCountVO.setPersonalSocAmount(personalSocAmount);
        empSocTransformCountVO.setPersonalPfAmount(personalPfAmount);
        empSocTransformCountVO.setCompanySocAmount(companySocAmount);
        empSocTransformCountVO.setCompanyPfAmount(companyPfAmount);
        empSocTransformCountVO.setAllAmount(allAmount);
        return empSocTransformCountVO;
    }

    @Override
    public EmpSocListQueryEnumVO getEmpSocListQueryEnum(String companyId, TokenUser tokenUser) {
        EmpSocListQueryEnumVO empSocListQueryEnumVO = new EmpSocListQueryEnumVO();
        Map<String, String> socProgMap;
        // 拿到人员类型的枚举
        Map<String, Integer> empPostTypeMap = new HashMap<>(16);
        List<DictItemDO> list = adminProviderService.selectAllDictItem(null, POST_TYPE, tokenUser);
        for (DictItemDO dictItem : list) {
            empPostTypeMap.put(dictItem.getDictItemKey(), Integer.parseInt(dictItem.getDictItemValue()));
        }
        // 缴费类型枚举
        Map<String, Integer> socPayCostTypeMap = new HashMap<>(16);
        SocPayCostType[] socPayCostTypeArrays = SocPayCostType.values();
        for (SocPayCostType socPayCostType : socPayCostTypeArrays) {
            socPayCostTypeMap.put(socPayCostType.getDesc(), socPayCostType.getValue());
        }
        // 拿到人员状态的枚举
        Map<String, Integer> empSocStatusMap = new HashMap<>(16);
        EmpSocStatus[] EmpSocStatusArrays = EmpSocStatus.values();
        for (EmpSocStatus empSocStatus : EmpSocStatusArrays) {
            empSocStatusMap.put(empSocStatus.getDesc(), empSocStatus.getValue());
        }
        empSocListQueryEnumVO.setSocPayCostTypeMap(socPayCostTypeMap);
        empSocListQueryEnumVO.setEmpPostTypeMap(empPostTypeMap);
        empSocListQueryEnumVO.setEmpSocStatusMap(empSocStatusMap);
        // 查询所有参保方案
        List<SocProgDO> socProgDOList = socProgService.selectSocProgByCompanyId(companyId, tokenUser);
        socProgMap = socProgDOList.stream().collect(Collectors.toMap(SocProgDO::getProgName, SocProgDO::getId));
        socProgMap.put("无参保方案", "100");
        empSocListQueryEnumVO.setSocProgMap(socProgMap);
        // 查询这个公司下的所有参保方案
        return empSocListQueryEnumVO;
    }

    @Override
    public BigDecimal mantissaProcessing(BigDecimal bigDecimal, Integer mantissaProcessingType) {
        if (ObjectUtils.isEmpty(mantissaProcessingType)) {
            return bigDecimal;
        }
        switch (mantissaProcessingType) {
            // 0 不做处理,默认四舍五入保留两位小数
            case 0:
                // 四舍五入到分,即保留2位小数
            case 3:
                bigDecimal = bigDecimal.setScale(2, RoundingMode.HALF_UP);
                break;
            // 四舍五入到元,即保留0位小数
            case 1:
                bigDecimal = bigDecimal.setScale(0, RoundingMode.HALF_UP);
                break;
            // 四舍五入到角,即保留1位小数
            case 2:
                bigDecimal = bigDecimal.setScale(1, RoundingMode.HALF_UP);
                break;
            // 四舍五入到厘,即保留3位小数
            case 4:
                bigDecimal = bigDecimal.setScale(3, RoundingMode.HALF_UP);
                break;
            // 四舍五入到小数点后四位
            case 5:
                bigDecimal = bigDecimal.setScale(4, RoundingMode.HALF_UP);
                break;
            // 见厘进分,即保留2位小数
            case 6:
                bigDecimal = bigDecimal.setScale(2, RoundingMode.UP);
                break;
            // 见分进角,即保留1位小数
            case 7:
                bigDecimal = bigDecimal.setScale(1, RoundingMode.UP);
                break;
            // 见角进元,即保留0位小数
            case 8:
                bigDecimal = bigDecimal.setScale(0, RoundingMode.UP);
                break;
            // 见角舍去,即保留0位小数
            case 9:
                bigDecimal = bigDecimal.setScale(0, RoundingMode.DOWN);
                break;
            // 见分舍去,即保留1位小数
            case 10:
                bigDecimal = bigDecimal.setScale(1, RoundingMode.DOWN);
                break;
            // 见厘舍去
            case 11:
                bigDecimal = bigDecimal.setScale(2, RoundingMode.DOWN);
                break;
            default:
                throw new ParamException("无此种位数处理类型");
        }
        return bigDecimal;
    }

    /**
     * 把英文名转化为数据
     *
     * @param enName 英文名
     * @return 数据
     */
    private String enNameToDate2(String enName, EmpSocInfoListVO empSocInfoListVO, BigDecimal differenceAmount) {
        String result;
        switch (enName) {
            // 序号
            case INDEX:
                result = empSocInfoListVO.getIndex() + "";
                break;
            // 姓名
            case EMP_NAME:
                result = empSocInfoListVO.getName();
                break;
            // 手机号
            case PHONE:
                result = empSocInfoListVO.getPhone();
                break;
            // 渠道
            case CHANNEL_NAME:
                result = empSocInfoListVO.getChannelName();
                break;
            // 户口类型
            case REG_TYPE:
                if (!StringUtils.isEmpty(empSocInfoListVO.getRegType())) {
                    result = RegTypeEnum.find(Integer.parseInt(empSocInfoListVO.getRegType())).getDesc();
                } else {
                    result = "";
                }
                break;
            // 身份证号
            case ID_CARD:
                result = empSocInfoListVO.getIdCard();
                break;
            // 社保状态
            case SOC_STATE:
                Integer empSocStatus = empSocInfoListVO.getEmpSocStatus();
                if (ObjectUtils.isEmpty(empSocStatus)) {
                    result = "未参保";
                } else {
                    result = EmpSocStatus.find(empSocStatus).getDesc();
                }
                break;
            // 医保状态
            case ME_STATE:
                Integer empMeStatus = empSocInfoListVO.getEmpMeStatus();
                if (ObjectUtils.isEmpty(empMeStatus)) {
                    result = "未参保";
                } else {
                    result = EmpSocStatus.find(empMeStatus).getDesc();
                }
                break;
            // 公积金状态
            case PF_STATE:
                Integer empPfStatus = empSocInfoListVO.getEmpPfStatus();
                if (ObjectUtils.isEmpty(empPfStatus)) {
                    result = "未参保";
                } else {
                    result = EmpSocStatus.find(empPfStatus).getDesc();
                }
                break;
            // 人员类型
            case POST_TYPE:
                result = PostType.find(empSocInfoListVO.getPostType()).getDesc();
                break;
            // 参保方案
            case SOC_PROG_NAME:
                result = empSocInfoListVO.getProgName();
                break;
            // 参保城市
            case SOC_CITY_NAME:
                result = empSocInfoListVO.getSocCityName();
                break;
            // 参保时间
            case SOC_DATE:
                result = empSocInfoListVO.getYear() + "-" + empSocInfoListVO.getMonth();
                break;
            // 缴费类型
            case PAY_COST_TYPE:
                result = SocPayCostType.find(empSocInfoListVO.getPayCostType()).getDesc();
                break;
            // 服务费
            case SERVICE_COST:
                BigDecimal serviceCost = empSocInfoListVO.getServiceCost();
                if (ObjectUtils.isEmpty(serviceCost)) {
                    result = "0";
                } else {
                    result = serviceCost.stripTrailingZeros().toPlainString();
                }
                break;
            // 滞纳金
            case FINE:
                BigDecimal fine = new BigDecimal("0");
                BigDecimal accumulationFundFine = empSocInfoListVO.getAccumulationFundFine();
                if (!ObjectUtils.isEmpty(accumulationFundFine)) {
                    fine = fine.add(accumulationFundFine);
                }
                BigDecimal socialSecurityFine = empSocInfoListVO.getSocialSecurityFine();
                if (!ObjectUtils.isEmpty(socialSecurityFine)) {
                    fine = fine.add(socialSecurityFine);
                }
                result = fine.stripTrailingZeros().toPlainString();
                break;
            case AMOUNT:
                BigDecimal amount = empSocInfoListVO.getCompanySocAmount().add(empSocInfoListVO.getCompanyPfAmount())
                        .add(empSocInfoListVO.getPersonalSocAmount()).add(empSocInfoListVO.getPersonalPfAmount())
                        .add(differenceAmount);
                if (!ObjectUtils.isEmpty(empSocInfoListVO.getServiceCost())) {
                    amount = amount.add(empSocInfoListVO.getServiceCost());
                }
                result = amount.stripTrailingZeros().toPlainString();
                break;
            default:
                result = "";
        }
        return result;
    }

    /**
     * 给我一个Date,我把日给你去掉,变成  多少年 多少月  01日
     *
     * @param date 时间
     * @return 去掉后面的天返回
     */
    private Date dateRemoveDay(Date date) {
        String[] yearAndMonth = DateUtils.getYearAndMonth(date);
        return DateKit8.parse(yearAndMonth[0] + "-" + yearAndMonth[1] + "-01", "yyyy-MM-dd");
    }


    /**
     * 根据参保方案的子项和付款归属修改参保信息中的金额
     */
    private void gatherAmountByPayAttribution(SocProgDO socProgDO, List<SocProgItemDO> empSocItemDOList,
                                              EmpSocInfoDO empSocInfoDOUpdate, Integer payAttribution, Integer itemType) {
        BigDecimal personalAmount = new BigDecimal("0");
        BigDecimal companyAmount = new BigDecimal("0");
        BigDecimal percent = new BigDecimal("0.01");
        for (SocProgItemDO socProgItemDO : empSocItemDOList) {
            BigDecimal cardinalityDefault = socProgItemDO.getCardinalityDefault();
            if (payAttribution == 1) {
                //只个人,并且方案是仅金额
                if (socProgDO.getOnlySocAmount()) {
                    personalAmount =
                            personalAmount.add(socProgItemDO.getAmountPersonal().add(socProgItemDO.getAmountCompany()));
                } else {
                    // 设置比例
                    personalAmount = personalAmount
                            .add(cardinalityDefault.multiply(socProgItemDO.getPersentPersonal().multiply(percent))
                                    .add(cardinalityDefault.multiply(socProgItemDO.getPersentCompany().multiply(percent))));
                }
            } else if (payAttribution == 2) {
                //只公司,并且方案是仅金额
                if (socProgDO.getOnlySocAmount()) {
                    companyAmount = companyAmount.add(socProgItemDO.getAmountPersonal().add(socProgItemDO.getAmountCompany()));
                } else {
                    // 设置比例
                    companyAmount = companyAmount
                            .add(cardinalityDefault.multiply(socProgItemDO.getPersentPersonal().multiply(percent))
                                    .add(cardinalityDefault.multiply(socProgItemDO.getPersentCompany().multiply(percent))));
                }
            } else {
                //个人公司都有,并且方案是仅金额
                if (socProgDO.getOnlySocAmount()) {
                    personalAmount = personalAmount.add(socProgItemDO.getAmountPersonal());
                    companyAmount = companyAmount.add(socProgItemDO.getAmountCompany());
                } else {
                    // 设置比例
                    personalAmount = personalAmount
                            .add(cardinalityDefault.multiply(socProgItemDO.getPersentPersonal().multiply(percent)));
                    companyAmount = companyAmount
                            .add(cardinalityDefault.multiply(socProgItemDO.getPersentCompany().multiply(percent)));
                }
            }
            personalAmount = mantissaProcessing(personalAmount, socProgItemDO.getMantissaProcPersonal());
            companyAmount = mantissaProcessing(companyAmount, socProgItemDO.getMantissaProcCompany());
        }
        if (SOC_ITEM_TYPE.equals(itemType)) {
            empSocInfoDOUpdate.setPersonalSocAmount(empSocInfoDOUpdate.getPersonalSocAmount().add(personalAmount));
            empSocInfoDOUpdate.setCompanySocAmount(empSocInfoDOUpdate.getCompanySocAmount().add(companyAmount));
        } else if (PF_ITEM_TYPE.equals(itemType)) {
            empSocInfoDOUpdate.setPersonalPfAmount(empSocInfoDOUpdate.getPersonalPfAmount().add(personalAmount));
            empSocInfoDOUpdate.setCompanyPfAmount(empSocInfoDOUpdate.getCompanyPfAmount().add(companyAmount));
        } else {
            throw new ParamException("子项类型不正确");
        }
    }

    /**
     * 补收补缴预览根据缴费所属填充金额
     */
    private void previewFillAmount(SocProgDO socProgDO, SocFillPreviewVO socFillPreviewVO, SocProgItemDO empSocItemDO, Integer payAttribution) {
        BigDecimal percent = new BigDecimal("0.01");
        BigDecimal cardinalityDefault = empSocItemDO.getCardinalityDefault();
        if (payAttribution == 1) {
            //只个人
            if (socProgDO.getOnlySocAmount()) {
                socFillPreviewVO.setAmountPersonal(empSocItemDO.getAmountPersonal().add(empSocItemDO.getAmountCompany()));
            } else {
                // 设置比例
                socFillPreviewVO.setAmountPersonal(cardinalityDefault.multiply(empSocItemDO.getPersentPersonal().multiply(percent))
                        .add(cardinalityDefault.multiply(empSocItemDO.getPersentCompany().multiply(percent))));
            }
            socFillPreviewVO.setAmountCompany(new BigDecimal("0"));
        } else if (payAttribution == 2) {
            //只公司
            if (socProgDO.getOnlySocAmount()) {
                socFillPreviewVO.setAmountCompany(empSocItemDO.getAmountPersonal().add(empSocItemDO.getAmountCompany()));
            } else {
                // 设置比例
                socFillPreviewVO.setAmountCompany(cardinalityDefault.multiply(empSocItemDO.getPersentPersonal().multiply(percent))
                        .add(cardinalityDefault.multiply(empSocItemDO.getPersentCompany().multiply(percent))));
            }
            empSocItemDO.setAmountPersonal(new BigDecimal("0"));
        } else {
            //个人公司都有
            if (socProgDO.getOnlySocAmount()) {
                empSocItemDO.setAmountPersonal(empSocItemDO.getAmountPersonal());
                empSocItemDO.setAmountCompany(empSocItemDO.getAmountCompany());
            } else {
                // 设置比例
                empSocItemDO.setAmountPersonal(cardinalityDefault.multiply(empSocItemDO.getPersentPersonal().multiply(percent)));
                empSocItemDO.setAmountCompany(cardinalityDefault.multiply(empSocItemDO.getPersentCompany().multiply(percent)));
            }
        }
        socFillPreviewVO.setAllAmount(socFillPreviewVO.getAmountCompany().add(socFillPreviewVO.getAmountPersonal()));
    }

    /**
     * 补收补缴 根据 缴费所属 填充 子项 金额
     */
    private void previewFillItemAmount(SocProgDO socProgDO, EmpSocItemDO empSocItemDO, SocProgItemDO mainEmpSocItemDO,
                                       Integer payAttribution, TokenUser tokenUser) {
        BigDecimal percent = new BigDecimal("0.01");
        BigDecimal cardinalityDefault = mainEmpSocItemDO.getCardinalityDefault();
        if (payAttribution == 1) {
            //只个人
            if (socProgDO.getOnlySocAmount()) {
                empSocItemDO.setAmountPersonal(mainEmpSocItemDO.getAmountPersonal().add(mainEmpSocItemDO.getAmountCompany()));
            } else {
                // 设置比例
                empSocItemDO.setAmountPersonal(cardinalityDefault.multiply(mainEmpSocItemDO.getPersentPersonal().multiply(percent))
                        .add(cardinalityDefault.multiply(mainEmpSocItemDO.getPersentCompany().multiply(percent))));
            }
            empSocItemDO.setAmountCompany(new BigDecimal("0"));
        } else if (payAttribution == 2) {
            //只公司
            if (socProgDO.getOnlySocAmount()) {
                empSocItemDO.setAmountCompany(mainEmpSocItemDO.getAmountPersonal().add(mainEmpSocItemDO.getAmountCompany()));
            } else {
                // 设置比例
                empSocItemDO.setAmountCompany(cardinalityDefault.multiply(mainEmpSocItemDO.getPersentPersonal().multiply(percent))
                        .add(cardinalityDefault.multiply(mainEmpSocItemDO.getPersentCompany().multiply(percent))));
            }
            empSocItemDO.setAmountPersonal(new BigDecimal("0"));
        } else {
            //个人公司都有
            if (socProgDO.getOnlySocAmount()) {
                empSocItemDO.setAmountPersonal(mainEmpSocItemDO.getAmountPersonal());
                empSocItemDO.setAmountCompany(mainEmpSocItemDO.getAmountCompany());
            } else {
                // 设置比例
                empSocItemDO.setAmountPersonal(cardinalityDefault.multiply(mainEmpSocItemDO.getPersentPersonal().multiply(percent)));
                empSocItemDO.setAmountCompany(cardinalityDefault.multiply(mainEmpSocItemDO.getPersentCompany().multiply(percent)));
            }
        }
        empSocItemDO.setId(null);
        // 尾数处理
        empSocItemDO.setAmountCompany(mantissaProcessing(empSocItemDO.getAmountCompany(), empSocItemDO.getMantissaProcCompany()));
        empSocItemDO.setAmountPersonal(mantissaProcessing(empSocItemDO.getAmountPersonal(), empSocItemDO.getMantissaProcPersonal()));
        empSocItemDO.preInsert(tokenUser.getUserId());
        empSocItemDO.setSiteId(tokenUser.getSiteId());
    }

    /**
     * 补差更新未来月参保信息
     */
    private void fillDifferenceUpdate(List<String> monthIdList, String socProgId, String companyId,
                                      Map<String, SocProgItemUpdateDTO> itemNameCardinalityMap,
                                      Boolean onlySocAmount, List<Date> monthDifferences, TokenUser tokenUser) {
        List<EmpSocInfoDO> empSocInfoList = empSocInfoService
                .selectUpdateFillDifferenceEmp(companyId, monthIdList, socProgId, tokenUser.getSiteId());
        List<String> dateStrList = monthDifferences.stream().map(DateUtils::getYearMonthStr).collect(Collectors.toList());
        empSocInfoList = empSocInfoList.stream().filter(empSocInfoDO -> {
            if (NORMAL_PAY_COST.getValue().equals(empSocInfoDO.getPayCostType())) {
                return true;
            }
            return dateStrList.contains(empSocInfoDO.getYear() + empSocInfoDO.getMonth());
        }).collect(Collectors.toList());
        for (EmpSocInfoDO empSocInfoDO : empSocInfoList) {
            BigDecimal companySocAmount = new BigDecimal("0");
            BigDecimal companyPfAmount = new BigDecimal("0");
            BigDecimal personalSocAmount = new BigDecimal("0");
            BigDecimal personalPfAmount = new BigDecimal("0");
            List<EmpSocItemDO> empSocItemList = empSocItemService.selectEmpSocItemByInfoId(empSocInfoDO.getId(), tokenUser.getSiteId());
            for (EmpSocItemDO empSocItemDO : empSocItemList) {
                // 拿到传进来的 此子项的新基数
                SocProgItemUpdateDTO socProgItemUpdateDTO = itemNameCardinalityMap.get(empSocItemDO.getItemName());
                if (!ObjectUtils.isEmpty(socProgItemUpdateDTO)) {
                    BigDecimal bigDecimal = empSocItemDO.getCardinalityDefault();
                    // 判断基数大小
                    if (bigDecimal.compareTo(socProgItemUpdateDTO.getCardinalityDefault()) <= 0) {
                        bigDecimal = socProgItemUpdateDTO.getCardinalityDefault();
                        empSocItemDO.setCardinalityDefault(bigDecimal);
                        if (!onlySocAmount) {
                            BigDecimal hundred = new BigDecimal("0.01");
                            empSocItemDO.setAmountPersonal(mantissaProcessing(bigDecimal.multiply(empSocItemDO.
                                    getPersentPersonal().multiply(hundred)), empSocItemDO.getMantissaProcPersonal()));
                            empSocItemDO.setAmountCompany(mantissaProcessing(bigDecimal.multiply(empSocItemDO.
                                    getPersentCompany().multiply(hundred)), empSocItemDO.getMantissaProcCompany()));
                        }
                    }
                    // 判断是否仅设置金额
                    if (onlySocAmount) {
                        if (socProgItemUpdateDTO.getAmountCompany().compareTo(empSocItemDO.getAmountCompany()) > 0) {
                            empSocItemDO.setAmountCompany(socProgItemUpdateDTO.getAmountCompany());
                        }
                        if (socProgItemUpdateDTO.getAmountPersonal().compareTo(empSocItemDO.getAmountPersonal()) > 0) {
                            empSocItemDO.setAmountPersonal(socProgItemUpdateDTO.getAmountPersonal());
                        }
                    }
                    if (SOC_ITEM_TYPE.equals(empSocItemDO.getItemType()) ||
                            ME_ITEM_TYPE.equals(empSocItemDO.getItemType())) {
                        personalSocAmount = personalSocAmount.add(empSocItemDO.getAmountPersonal());
                        companySocAmount = companySocAmount.add(empSocItemDO.getAmountCompany());
                    } else {
                        personalPfAmount = personalPfAmount.add(empSocItemDO.getAmountPersonal());
                        companyPfAmount = companyPfAmount.add(empSocItemDO.getAmountCompany());
                    }
                    empSocItemService.updateByIdSelective(empSocItemDO, tokenUser.getSiteId(), tokenUser.getUserId());
                } else {
                    if (SOC_ITEM_TYPE.equals(empSocItemDO.getItemType()) ||
                            ME_ITEM_TYPE.equals(empSocItemDO.getItemType())) {
                        personalSocAmount = personalSocAmount.add(empSocItemDO.getAmountPersonal());
                        companySocAmount = companySocAmount.add(empSocItemDO.getAmountCompany());
                    } else {
                        personalPfAmount = personalPfAmount.add(empSocItemDO.getAmountPersonal());
                        companyPfAmount = companyPfAmount.add(empSocItemDO.getAmountCompany());
                    }
                }
            }
            empSocInfoDO.setPersonalSocAmount(personalSocAmount);
            empSocInfoDO.setCompanySocAmount(companySocAmount);
            empSocInfoDO.setPersonalPfAmount(personalPfAmount);
            empSocInfoDO.setCompanyPfAmount(companyPfAmount);
            empSocInfoService.updateByIdSelective(empSocInfoDO, tokenUser.getSiteId(), tokenUser.getUserId());
        }

    }

    @Override
    public void saveSocPersonalEvent(EmpInfoDO empInfoDO, String year, String month, String type, TokenUser tokenUser) {
        String desc = "由管理员" + tokenUser.getUserName() + "确认" + type + ",确认时间为" + year + "-" + month;
        if ("增员".equals(type)) {
            personalEventService.autoSave(empInfoDO.to(EmpInfoVO.class), tokenUser, desc,
                    PersonalEventEnum.INCREASE_CONFIRM.getValue(), PersonalEventEnum.INCREASE_CONFIRM.getDesc());
        } else if ("减员".equals(type)) {
            personalEventService.autoSave(empInfoDO.to(EmpInfoVO.class), tokenUser, desc,
                    PersonalEventEnum.DECREASE_CONFIRM.getValue(), PersonalEventEnum.DECREASE_CONFIRM.getDesc());
        }
    }

    @Override
    public void checkCostBillByMonthId(String monthId, String month, TokenUser tokenUser) {
        List<CostBillDO> costBillList = costBillService.selectCostBillBySubjectId(monthId, tokenUser);
        if (!CollectionUtils.isEmpty(costBillList)) {
            throw new ParamException(month + "月参保管理已生成账单,无法进行操作");
        }
    }

    /**
     * 自定义设置一个empSocInfo对象
     */
    private void customEmpSocInfoDO(EmpSocInfoDO empSocInfoDO, EmpInfoDO empInfoDO, String currentMonthId,
                                    String companyId, SocProgDO socProgDO, String[] yearAndMonth,
                                    FillSocQuery fillSocQuery, String supplementType, BigDecimal bigDecimal) {
        empSocInfoDO.setId(null);
        empSocInfoDO.setEmpId(empInfoDO.getId());
        empSocInfoDO.setMonthId(currentMonthId);
        empSocInfoDO.setEmpSocStatus(EmpSocStatus.NORMAL_SOC.getValue());
        empSocInfoDO.setCompanyId(companyId);

        empSocInfoDO.setPlanFlag(true);
        empSocInfoDO.setProgId(socProgDO.getId());
        empSocInfoDO.setPayCostType(FILL_COLLECT.getValue());
        empSocInfoDO.setSupplementType(supplementType);
        if (SUPPLEMENT_TYPE_ONE.equals(supplementType)) {
            empSocInfoDO.setSocialSecurityFine(bigDecimal);
            empSocInfoDO.setCompanyPfAmount(new BigDecimal("0"));
            empSocInfoDO.setPersonalPfAmount(new BigDecimal("0"));
        } else if (SUPPLEMENT_TYPE_TWO.equals(supplementType)) {
            empSocInfoDO.setAccumulationFundFine(bigDecimal);
            empSocInfoDO.setCompanySocAmount(new BigDecimal("0"));
            empSocInfoDO.setPersonalSocAmount(new BigDecimal("0"));
        }
        empSocInfoDO.setYear(yearAndMonth[0]);
        empSocInfoDO.setMonth(yearAndMonth[1]);
        empSocInfoDO.setServiceCost(fillSocQuery.getServiceCost());
    }

    /**
     * 查询[参保管理]导出表头的[基础信息]和当前用户自定义选择的表头
     */
    private Map<String, Integer> exportBasicAndSelectItem(List<HeaderFieldsTemplateDO> headerBasic, String moduleCode,
                                                          String companyId, TokenUser tokenUser) {
        headerBasic.addAll(adminProviderService.selectByCodeAndGroup(moduleCode, "基础信息"));
        Map<String, Integer> selectHead = new HashMap<>();
        List<HeaderFieldsDO> selectHeadList = adminProviderService
                .selectByModuleCodeAndUser(companyId, moduleCode, tokenUser);
        if (!CollectionUtils.isEmpty(selectHeadList)) {
            selectHead = selectHeadList.stream()
                    .collect(Collectors.toMap(HeaderFieldsDO::getFieldName, HeaderFieldsDO::getSort));
        }
        return selectHead;
    }

    /**
     * 社保名单/社保名单导出,Query数据填充
     */
    private void buildEmpSocListQuery(EmpSocTransformQuery empSocTransformQuery) {
        if (empSocTransformQuery.getStopSocDate() != null) {
            empSocTransformQuery.setStopSocDate(dateRemoveDay(empSocTransformQuery.getStopSocDate()));
        }
        if (empSocTransformQuery.getSealedDate() != null) {
            empSocTransformQuery.setSealedDate(dateRemoveDay(empSocTransformQuery.getSealedDate()));
        }
        if (!StringUtils.isEmpty(empSocTransformQuery.getEmpSocStatusString())) {
            String[] split = empSocTransformQuery.getEmpSocStatusString().split(",");
            List<Integer> empSocStatusList = new ArrayList<>();
            for (String status : split) {
                empSocStatusList.add(Integer.parseInt(status));
            }
            empSocTransformQuery.setEmpSocStatusList(empSocStatusList);
        }
    }

    /**
     * 社保名单查询和导出赋值最近一条参保记录的金额
     */
    private void socListAmountInfo(List<EmpSocTransformVO> socList, String companyId, TokenUser tokenUser) {
        List<DictItemDO> list = adminProviderService.selectAllDictItem(null, POST_TYPE, tokenUser);
        Map<String, DictItemDO> dictMap = list.stream().collect(Collectors.toMap(DictItemDO::getDictItemValue, v -> v));
        for (EmpSocTransformVO empSocTransformVO : socList) {
            Integer postType = empSocTransformVO.getPostType();
            DictItemDO dictItem = dictMap.get(postType + "");
            empSocTransformVO.setPostTypeStr(dictItem.getDictItemKey());
            EmpSocInfoDO empSocInfoDO = empSocInfoService.getEmpSocInfoByEmpId(empSocTransformVO.getEmpId(),
                    companyId, tokenUser.getSiteId());
            if (!ObjectUtils.isEmpty(empSocInfoDO)) {
                empSocTransformVO.setCompanySocAmount(empSocInfoDO.getCompanySocAmount());
                empSocTransformVO.setCompanyPfAmount(empSocInfoDO.getCompanyPfAmount());
                empSocTransformVO.setPersonalSocAmount(empSocInfoDO.getPersonalSocAmount());
                empSocTransformVO.setPersonalPfAmount(empSocInfoDO.getPersonalPfAmount());
                empSocTransformVO.setSocAmount(empSocInfoDO.getCompanySocAmount().add(empSocInfoDO.getPersonalSocAmount()));
                empSocTransformVO.setPfAmount(empSocInfoDO.getCompanyPfAmount().add(empSocInfoDO.getPersonalPfAmount()));
                empSocTransformVO.setPlanFlag(empSocInfoDO.getPlanFlag());
            }
            Date socIncreaseDate = empSocTransformVO.getSocIncreaseDate();
            Date pfIncreaseDate = empSocTransformVO.getPfIncreaseDate();
            Date meIncreaseDate = empSocTransformVO.getMeIncreaseDate();
            Date minDate = DateUtils.compareMin(socIncreaseDate, pfIncreaseDate, meIncreaseDate);
            empSocTransformVO.setSocDate(minDate);
        }
    }
}
